SlmMail: transports to send emails with Zend\Mail

Yesterday, I released the Release Candidate number 1 of SlmMail. SlmMail provides API implementations of the largest email service providers. So if your sendmail or SMTP fails, include SlmMail and offload the risk of sending emails to others. In the last years, emails must be secured with all kind of mechanisms like SPF, DKIM and DMARC. It just costs a lot of time and knowledge to maintain your email stack, so that’s why email service providers comes to help.

SlmMail has implemented the API of various of the largest players in the field:

  • AlphaMail
  • Amazon SES
  • Elastic Email
  • Mailgun
  • Mandrill
  • Postmark
  • Postage
  • Send Grid

The main benefit of SlmMail is these integrations are possible without any modification to your message objects or service layer! If you handled the transport with dependency injection (as you should do!), then you simply inject another Transport implementation. And guess, it works out of the box.

To give some help, here is a use case of email sending with an attachment. Say in your ecommerce application you want to send a confirmation of the order to the user, with a pdf file attached. Say this business logic happens inside a service layer and the transport is injected.

use Zend\Mail\TransportInterface;
use Zend\View\Renderer\RendererInterface;

use Zend\Mime\Part    as MimePart;
use Zend\Mime\Message as MimeMessage;
use Zend\Mail\Message;

use Application\Model\User;
use Application\Model\Order;

class EmailService
{
    protected $transport;
    protected $renderer;

    public function __construct(TransportInterface $transport, RendererInterface $renderer)
    {
        $this->transport = $transport;
        $this->renderer  = $renderer;
    }

    public function sendOrderConfirmation(User $user, Order $order, $pdfPath)
    {
        $message = new Message;
        $message->setSubject('Order confirmation');
        $message->setTo($user->getEmail(), $user->getName());
        $message->setFrom($this->getFromEmail(), $this->getFromName());

        $content = $this->renderer->render('email/order/confirmation-plain', array(
            'user'  => $user,
            'order' => $order,
        ));
        $text = new MimePart($content);
        $text->type = 'text/plain';

        $content = $this->renderer->render('email/order/confirmation-html', array(
            'user'  => $user,
            'order' => $order,
        ));
        $html = new MimePart($content);
        $html->type = 'text/html';

        $pdf  = new MimePart(fopen($pdfPath, 'r'));
        $pdf->type = 'application/pdf';

        $body = new MimeMessage;
        $body->setParts(array($text, $html, $pdf));

        $message->setBody($body);
        $this->transport->send($message);
    }

    // More methods like getFromEmail() etc
}

This service layer is transport method agnostic. Thus, any email transport can be injected. Say, you first have a simple sendmail transport. In your Module.php you configure a factory to inject these dependencies into your service class:

public function getServiceConfig()
{
    return array(
        'factories' => array(
            'email-service' => function ($sl) {
                $transport = new \Zend\Mail\Transport\Sendmail;
                $renderer  = $sl->get('ViewRenderer');

                return new Service\EmailService($transport, $renderer);
            }
        ),
    );
}

Well, and if you want to drop in an SlmMail transport, you only have to update your factory to inject the right transport. For example, the Mandrill transport is easy to inject:

public function getServiceConfig()
{
    return array(
        'factories' => array(
            'email-service' => function ($sl) {
                $transport = $sl->get('SlmMail\Mail\Transport\MandrillTransport');
                $renderer  = $sl->get('ViewRenderer');

                return new Service\EmailService($transport, $renderer);
            }
        ),
    );
}

And the service, including the sending of the pdf file attachment, works as expected!