Practical symfony

Day 16: The Mailer

About

You are currently reading "Practical symfony" which is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License license.

Jobeet Links

Symfony 2.0 Preview Release

Chapter Content

Sending simple Emails

Configuration

Factories

Delivery Strategy

Mail Transport

Testing Emails

See you Tomorrow

symfony training
Be trained by symfony experts
Apr 12: Paris (What's new in 1.3/1.4 - Français)
Apr 21: Paris (1.4 + Doctrine - Français)
Apr 28: Online (What's new in 1.3/1.4 - Français)
and more...

Search


powered by google
You are currently browsing "Practical symfony" in English for the 1.4 version - Propel edition - Switch to version: - Switch to ORM: - Switch to language:
Creative Commons License This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.
Practical symfony (Propel edition)
Buy Practical symfony (Propel edition) from amazon.com
You have been redirected to the symfony 1.4 documentation.
Both symfony 1.3 and symfony 1.4 share the same feature set and documentation.
Read about why we have two different versions.

Yesterday, we added a read-only web service to Jobeet. Affiliates can now create an account but it needs to be activated by the administrator before it can be used. In order for the affiliate to get its token, we still need to implement the email notification. That's what we will start doing today.

The symfony framework comes bundled with one of the best PHP emailing solution: Swift Mailer. Of course, the library is fully integrated with symfony, with some cool features added on top of its default features.

Symfony 1.3/1.4 uses Swift Mailer version 4.1.

Sending simple Emails

Let's start by sending a simple email to notify the affiliate when his account has been confirmed and to give him the affiliate token.

Replace the activate action with the following code:

// apps/backend/modules/affiliate/actions/actions.class.php
class affiliateActions extends autoAffiliateActions
{
  public function executeListActivate()
  {
    $affiliate = $this->getRoute()->getObject();
    $affiliate->activate();
 
    // send an email to the affiliate
    $message = $this->getMailer()->compose(
      array('jobeet@example.com' => 'Jobeet Bot'),
      $affiliate->getEmail(),
      'Jobeet affiliate token',
      <<<EOF
Your Jobeet affiliate account has been activated.
 
Your token is {$affiliate->getToken()}.
 
The Jobeet Bot.
EOF
    );
 
    $this->getMailer()->send($message);
 
    $this->redirect('@jobeet_affiliate');
  }
 
  // ...
}

For the code to work properly, you should change the jobeet@example.com email address to a real one.

Email management in symfony is centered around a mailer object, which can be retrieved from an action with the getMailer() method.

The compose() method takes four arguments and returns an email message object:

Sending the message is then as simple as calling the send() method on the mailer instance and passing the message as an argument. As a shortcut, you can only compose and send an email in one go by using the composeAndSend() method.

The email message is an instance of the Swift_Message class. Refer to the Swift Mailer official documentation to learn more about this object, and how to do more advanced stuff like attaching files.

Configuration

By default, the send() method tries to use a local SMTP server to send the message to the recipient. Of course, as many things in symfony, this is totally configurable.

Factories

During the previous days, we have already talked about symfony core objects like the user, request, response, or the routing. These objects are automatically created, configured, and managed by the symfony framework. They are always accessible from the sfContext object, and like many things in the framework, they are configurable via a configuration file: factories.yml. This file is configurable by environment.

When the sfContext initializes the core factories, it reads the factories.yml file for the class names (class) and the parameters (param) to pass to the constructor:

response:
  class: sfWebResponse
  param:
    send_http_headers: false

In the above snippet, to create the response factory, symfony instantiates a sfWebResponse object and passes the send_http_headers option as a parameter.

Delivery Strategy

Like many other core symfony objects, the mailer is a factory. So, it is configured in the factories.yml configuration file. The default configuration reads as follows:

mailer:
  class: sfMailer
  param:
    logging:           %SF_LOGGING_ENABLED%
    charset:           %SF_CHARSET%
    delivery_strategy: realtime
    transport:
      class: Swift_SmtpTransport
      param:
        host:       localhost
        port:       25
        encryption: ~
        username:   ~
        password:   ~

When creating a new application, the local factories.yml configuration file overrides the default configuration with some sensible defaults for the env and test environments:

test:
  mailer:
    param:
      delivery_strategy: none
 
dev:
  mailer:
    param:
      delivery_strategy: none

The delivery_strategy setting tells symfony how to deliver emails. By default, symfony comes with four different strategies:

Whatever the strategy, emails are always logged and available in the "mailer" panel in the web debug toolbar.

Mail Transport

Mail messages are actually sent by a transport. The transport is configured in the factories.yml configuration file, and the default configuration uses the SMTP server of the local machine:

transport:
  class: Swift_SmtpTransport
  param:
    host:       localhost
    port:       25
    encryption: ~
    username:   ~
    password:   ~

Swift Mailer comes bundled with three different transport classes:

The "Transport Types" section of the Swift Mailer official documentation describes all you need to know about the built-in transport classes and their different parameters.

Testing Emails

Now that we have seen how to send an email with the symfony mailer, let's write some functional tests to ensure we did the right thing. By default, symfony registers a mailer tester (sfMailerTester) to ease mail testing in functional tests.

Replace the affiliate functional test file for the backend application with the following code:

// test/functional/backend/affiliateActionsTest.php
include(dirname(__FILE__).'/../../bootstrap/functional.php');
 
$browser = new JobeetTestFunctional(new sfBrowser());
$browser->loadData();
 
$browser->
  info('1 - When validating an affiliate, an email must be sent with its token')->
 
  get('/affiliate/new')->
  click('activate', array(), array('position' => 1))->
  with('mailer')->begin()->
    checkHeader('Subject', '/Jobeet affiliate token/')->
    checkBody('/Your token is symfony/')->
  end()
;

For the previous code to work, you need to copy yesterday's fixture file (data/fixtures/030_affiliates.yml) in the test/fixtures/ directory.

Each sent email can be tested with the help of the checkHeader() and checkBody() methods. The second argument of checkHeader() and the first argument of checkBody() can be one of the following:

By default, checks are done on the first email sent. If several emails have been sent, you can choose the one you want to test with the withMessage() method. The withMessage() takes a recipient as its first argument. It also takes a second argument to indicate which email you want to test if several ones have been sent to the same recipient.

Like other built-in testers, you can see the raw message by calling the debug() method.

See you Tomorrow

Tomorrow, we will implement the last missing feature of the Jobeet website, the search engine.

Day 17: Search »
« Day 15: Web Services

Questions & Feedback

If you find a typo or an error, please register and open a ticket.

If you need support or have a technical question, please post to the official user mailing-list.

The Sensio Labs Network

Since 1998, Sensio Labs has been promoting the Open-Source software movement by providing quality web application development, training, consulting.
Sensio Labs also supports several large Open-Source projects.