Monday, January 06, 2014

How to send an email with symfony 1.3/1.4 and Gmail – - Développement & Conseil Symfony

One nice feature coming with symfony 1.3 & 1.4 is an embedded mail system based on Swift Mailer 4.1
Providing a mail system into symfony’s core has been a wide debate since symfony 1.0. The 1st stable version of the framework was coming with an unperfect but operational way of sending emails based on phpMailer. Thus, following the decoupling philosophy, this feature was removed on symfony 1.1 and 1.2. The old 1.0 email system is actually still supported through sfCompat10Plugin but it’s now a deprecated module and has completely disappear on symfony 1.4.
With the recent handover of Swift Mailer by Fabien Potencier, a natural synergy between symfony and Swift Mailer has been initiated. Swift Mailer still could be used on any PHP projects but will also come as the default mailing system of symfony 1.3 & 1.4.
Let’s play with it a little, using a Gmail account…

Disclaimer : I assume you already know some basics of symfony. I must recommend you to learn Jobeet tutorial if you get lost starting this quick how-to.

Part 1: The configuration side

The mailer configuration is application-based (frontend, backend etc.) and can be set differently for each environment (prod, dev, test etc.) of your project.
All the configuration has to be done on the factories.yml file. There, you can set two aspects of the mailer : the delivery strategy and the transport of the messages.
The delivery strategy
The delivery strategy is defined by the delivery_strategy option. This one allows the following values :
  • realtime: sending the message directly
  • spool: using a queue
  • single_address: sending emails to a specific address (on a dev environment)
  • none: no email is sent (useful on a test environment)
Don’t forget to fill a delivery_address option if you plan to use single_address mode.
The transport
Swift Mailer supports 3 transports (or way of sending messages) modes :
  • SMTP: allows authentification and encryption (uses Swift_SmtpTransport class)
  • Sendmail: using a local MTA such as Sendmail
  • Mail: similar as PHP native mail() function
 #/myproject/apps/frontend/config/factories.yml prod:   mailer:     param:       delivery_strategy: realtime  test:   mailer:     param:       delivery_strategy:  none   dev:   mailer:     param:       delivery_strategy:  single_address       delivery_address:  your_email      all:   mailer:     param:       transport:         class: Swift_SmtpTransport         param:           host:           port:       465           encryption: ssl           username: your_gmail_account           password: your_gmail_password 
This example is quite explicit. A common smtp transport has been set for each environment (under the « all » section). Note that Gmail SMTP servers need to be called through port 465 using ssl encryption.
Thanks to configuration cascade mechanism, each environment can use this transport differently :
  • on test environment, no messages are sent but emails are logged and sfTesterMailer can be used on functional tests.
  • dev environment sends emails to a unique address (e.g. the developer’s one)
  • prod environment is set to work on real conditions : messages are consciously sent to their recipients
With anything correctly set, let’s now compose and send messages.

Part 2: The message side

Unlike the symfony 1.0 mail mechanism, composing and sending a message methods are supported by the context not by the controller. However, accessing to the mailer on an action is possible through the proxy method sfAction::getMailer(). So, on an action, symfony mailer can be accessed this way:
elsewhere the mailer can be retrieved that way:
Just compose and send
sfMailer comes with a very quick and simple method to send emails.
$this->getMailer()->composeAndSend('', '', 'Subject', 'Body');
Complex messages
If you need to create more complex messages, sfMailer class gives access to all SwiftMailer great functionalities such as multipart emails, attachments, multi-recipients etc.
Consider the following example with a multipart message.
 #/myproject/apps/frontend/modules/mymodule/actions.class.php  public function executeSend($request) { ...     $message = $this->getMailer()->compose();     $message->setSubject($params['subject']);     $message->setTo($params['to']));     $message->setFrom($params['from']);      $html = $this->getPartial('mymodule/myTemplateHtml',$params);     $message->setBody($html, 'text/html');     $text = $this->getPartial('mymodule/myTemplateTxt',$params);     $message->addPart($text, 'text/plain');          $this->getMailer()->send($message); ... } 
Please note that the previous example is not complete, assuming that $params is an array of data which can come from the database or a form. One good practice would be refactoring this mailer piece of code on a protected method outside the action method or more likely on a reusable custom library.
That’s all for today. Don’t hesitate taking a look to sfMailer class and Swift Mailer documentation to know more about all the new mail capabilities available on symfony.

No comments: