Skip to content

Commit

Permalink
Merge pull request #73 from juriansluiman/mandrill-scheduling
Browse files Browse the repository at this point in the history
Add support for scheduled emails in Mandrill
  • Loading branch information
Jurian Sluiman committed Jun 9, 2014
2 parents a9e3c82 + c30fec3 commit 200b3ef
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 14 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# CHANGELOG

## 1.5.0

- You can now schedule Mandrill emails in the future by using the optional `sendAt` variable in both `send` and
`sendTemplate` methods.
- `getScheduledMessages`, `cancelScheduledMessage` and `rescheduleMessage` methods have been also added to the
Mandrill service to handle those messages.

## 1.4.1

- Fix Sendgrid attachment issues with Outlook clients
Expand Down
30 changes: 28 additions & 2 deletions docs/Mandrill.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ Mandrill service will filter unknown options. Unsupported options with throw an
* merge: (boolean) whether to evaluate merge tags in the message. Will automatically be set to true if either merge_vars or global_merge_vars are provided.
* google_analytics_domains: (array) an array of strings indicating for which any matching URLs will automatically have Google Analytics parameters appended to their query string automatically.
* google_analytics_campaign: (string) optional string indicating the value to set for the utm_campaign tracking parameter. If this isn't provided the email's from address will be used instead.
* view_content_link: (boolean): whether or not to remove content logging for sensitive emails

#### Tags

Expand Down Expand Up @@ -144,6 +145,28 @@ $message->setTemplate('foo')
->setTemplateContent(array('header' => '<header><h1>This is an example</h1></header>'))
```

#### Scheduled messages

Mandrill natively supports the ability to schedule message in the future. You can schedule a message using the optional
sendAt parameter in both `send` and `sendTemplate` methods:

```php
$sendAt = new DateTime();
$sendAt->modify('+1 day'); // send message in 1 day

$message = new \SlmMail\Mail\Message\Mandrill();

$mandrillService->send($message, $sendAt);
```

You can also use the various `getScheduledMessages`, `cancelScheduledMessage` and `rescheduleMessage` from the
Mandrill service to interact with this API.

Internally, the date is automatically converted to UTC and to the appropriate date format that Mandrill is expected.

Please note that this feature of Mandrill introduces additional fees, and require you to have a positive balance
account ([see here for more details](http://help.mandrill.com/entries/24331201-Can-I-schedule-a-message-to-send-at-a-specific-time-).

### Use service locator

If you have access to the service locator, you can retrieve the Mandrill transport:
Expand Down Expand Up @@ -176,9 +199,12 @@ $ping = $mandrillService->pingUser(); // Example

Messages functions:

* `send(Message $message)`: used by transport layer, $message instance of `Zend\Mail\Message` ([docs](https://mandrillapp.com/api/docs/messages.html#method=send))
* `sendTemplate(Message $message)`: used by transport layer if a $message has a template ([docs](https://mandrillapp.com/api/docs/messages.html#method=send-template))
* `send(Message $message, DateTime $sendAt = null)`: used by transport layer, $message instance of `Zend\Mail\Message` ([docs](https://mandrillapp.com/api/docs/messages.html#method=send))
* `sendTemplate(Message $message, DateTime $sendAt = null)`: used by transport layer if a $message has a template ([docs](https://mandrillapp.com/api/docs/messages.html#method=send-template))
* `getMessageInfo($id)`: get all the information about a message by its Mandrill id ([docs](https://mandrillapp.com/api/docs/messages.JSON.html#method=info))
* `getScheduledMessages($to = '')`: get all the scheduled messages, optionally filtered by an email To address ([docs](https://mandrillapp.com/api/docs/messages.JSON.html#method=list-scheduled))
* `cancelScheduledMessage($id = '')`: cancel a scheduled message by its Mandrill id ([docs](https://mandrillapp.com/api/docs/messages.JSON.html#method=cancel-scheduled))
* `rescheduleMessage($id, DateTime $sendAt)`: reschedule an already scheduled message by its Mandrill id and new date ([docs](https://mandrillapp.com/api/docs/messages.JSON.html#method=reschedule))

Users functions:

Expand Down
5 changes: 3 additions & 2 deletions src/SlmMail/Mail/Message/Mandrill.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ class Mandrill extends Message
'track_clicks',
'track_opens',
'tracking_domain',
'url_strip_qs'
'url_strip_qs',
'view_content_link'
);

/**
Expand All @@ -78,7 +79,7 @@ class Mandrill extends Message
protected $tags = array();

/**
* @var string
* @var string|null
*/
protected $template;

Expand Down
85 changes: 75 additions & 10 deletions src/SlmMail/Service/MandrillService.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@

namespace SlmMail\Service;

use DateTime;
use DateTimeZone;
use SlmMail\Mail\Message\Mandrill as MandrillMessage;
use SlmMail\Service\AbstractMailService;
use Zend\Http\Request as HttpRequest;
Expand Down Expand Up @@ -77,15 +79,17 @@ public function __construct($apiKey)

/**
* @link https://mandrillapp.com/api/docs/messages.html#method=send
* {@inheritDoc}
* @param Message $message
* @param DateTime|null $sendAt
* @return array
*/
public function send(Message $message)
public function send(Message $message, DateTime $sendAt = null)
{
if ($message instanceof MandrillMessage && $message->getTemplate()) {
return $this->sendTemplate($message);
}

$response = $this->prepareHttpClient('/messages/send.json', $this->parseMessage($message, false))
$response = $this->prepareHttpClient('/messages/send.json', $this->parseMessage($message, $sendAt))
->send();

return $this->parseResponse($response);
Expand All @@ -96,11 +100,12 @@ public function send(Message $message)
*
* @link https://mandrillapp.com/api/docs/messages.html#method=send-template
* @param MandrillMessage $message
* @param DateTime|null $sendAt
* @return array
*/
public function sendTemplate(MandrillMessage $message)
public function sendTemplate(MandrillMessage $message, DateTime $sendAt = null)
{
$response = $this->prepareHttpClient('/messages/send-template.json', $this->parseMessage($message, true))
$response = $this->prepareHttpClient('/messages/send-template.json', $this->parseMessage($message, $sendAt))
->send();

return $this->parseResponse($response);
Expand All @@ -121,6 +126,57 @@ public function getMessageInfo($id)
return $this->parseResponse($response);
}

/**
* Get the scheduled messages, optionally filtered by an email To address
*
* @link https://mandrillapp.com/api/docs/messages.JSON.html#method=list-scheduled
* @param string $to
* @return array
*/
public function getScheduledMessages($to = '')
{
$response = $this->prepareHttpClient('/messages/list-scheduled.json', array('to' => $to))
->send();

return $this->parseResponse($response);
}

/**
* Cancel a scheduled message using the mail identifier (you get it by from send methods or getScheduledMessages method)
*
* @link https://mandrillapp.com/api/docs/messages.JSON.html#method=cancel-scheduled
* @param string $id
* @return array
*/
public function cancelScheduledMessage($id)
{
$response = $this->prepareHttpClient('/messages/cancel-scheduled.json', array('id' => $id))
->send();

return $this->parseResponse($response);
}

/**
* Reschedule an already scheduled message to a new date
*
* @link https://mandrillapp.com/api/docs/messages.JSON.html#method=reschedule
* @param string $id
* @param DateTime $sendAt
* @return array
*/
public function rescheduleMessage($id, DateTime $sendAt)
{
// Mandrill needs to have date in UTC, using this format
$sendAt->setTimezone(new DateTimeZone('UTC'));

$parameters = array('id' => $id, 'send_at' => $sendAt->format('Y-m-d H:i:s'));

$response = $this->prepareHttpClient('/messages/reschedule.json', $parameters)
->send();

return $this->parseResponse($response);
}

/**
* ------------------------------------------------------------------------------------------
* USERS
Expand Down Expand Up @@ -737,15 +793,17 @@ public function renderTemplate($name, array $content = array(), array $variables
}

/**
* @param Message $message
* @param bool $isTemplate
* @param Message $message
* @param DateTime|null $sendAt
* @throws Exception\RuntimeException
* @return array
*/
private function parseMessage(Message $message, $isTemplate)
private function parseMessage(Message $message, DateTime $sendAt = null)
{
$hasTemplate = ($message instanceof MandrillMessage && null !== $message->getTemplate());

$from = $message->getFrom();
if (($isTemplate && count($from) > 1) || (!$isTemplate && count($from) !== 1)) {
if (($hasTemplate && count($from) > 1) || (!$hasTemplate && count($from) !== 1)) {
throw new Exception\RuntimeException(
'Mandrill API requires exactly one from sender (or none if send with a template)'
);
Expand Down Expand Up @@ -786,14 +844,15 @@ private function parseMessage(Message $message, $isTemplate)
}

$replyTo = $message->getReplyTo();

if (count($replyTo) > 1) {
throw new Exception\RuntimeException('Mandrill has only support for one Reply-To address');
} elseif (count($replyTo)) {
$parameters['message']['headers']['Reply-To'] = $replyTo->rewind()->toString();
}

if ($message instanceof MandrillMessage) {
if ($isTemplate) {
if ($hasTemplate) {
$parameters['template_name'] = $message->getTemplate();

foreach ($message->getTemplateContent() as $key => $value) {
Expand Down Expand Up @@ -868,6 +927,12 @@ private function parseMessage(Message $message, $isTemplate)
);
}

if (null !== $sendAt) {
// Mandrill needs to have date in UTC, using this format
$sendAt->setTimezone(new DateTimeZone('UTC'));
$parameters['send_at'] = $sendAt->format('Y-m-d H:i:s');
}

return $parameters;
}

Expand Down

0 comments on commit 200b3ef

Please sign in to comment.