Version 5 supported

Email

Creating and sending email in Silverstripe CMS is done using the Email class. This document covers how to create an Email instance and customise it with an HTML template.

Configuration

Silverstripe CMS provides an API over the top of symfony/mailer which comes with an extensive list of "transports" for sending mail via different services such as SMTP, Gmail, and Amazon SES.

Email configuration is done using Symfony's DSN configuration string which is used to select which transport is used and any required configuration such as username and password. In Silverstripe, this is done with either an environment variable or yml configuration.

The Sendmail transport is the most common one and is used by default in Silverstripe. The sendmail binary is widely available across most Linux/Unix servers. By default the sendmail command used is /usr/sbin/sendmail -bs, but this can be configured as part of the DSN.

Alternatively you can provide a different DSN to select any of the Transport classes provided natively by symfony/mailer or other compatible third-party transports. For more information and to see what other transports are available see the symfony/mailer transport types.

The format for the DSN is exactly as defined in the symfony docs linked above. Some common examples are listed below.

To set the DSN string in an environment variable (recommended):

# .env
MAILER_DSN="<my-dsn>"

To set the DSN string in project yml:

# app/_config/mailer-project.yml
---
Name: mailer-project
After: 'mailer'
---
SilverStripe\Core\Injector\Injector:
  Symfony\Component\Mailer\Transport\TransportInterface:
    constructor:
      dsn: '<my-dsn>'

The configuration priority order is as follows, from highest to lowest:

  • The MAILER_DSN environment variable
  • Project yml containing After: 'mailer'
  • The default DSN of sendmail://default which will use /usr/sbin/sendmail -bs

Common DSN strings

To configure SMTP

# .env
MAILER_DSN="smtp://user:pass@smtp.example.com:1234"

To configure a different sendmail binary and command

# .env
MAILER_DSN="sendmail://default?command=/path/to/mysendmailbinary%20-t"

To suppress all emails

# .env
MAILER_DSN="null://default"

Read more about other available DSN strings in the symfony documentation

Testing that email works

You must ensure emails are being sent from your production environment. You can do this by testing that the Lost password form available at /Security/lostpassword sends an email to your inbox, or with the following code snippet that can be run via a SilverStripe\Dev\BuildTask:

use SilverStripe\Control\Email\Email;

$email = Email::create($from, $to, $subject, $body);
$email->send();

Using the code snippet above also tests that the ability to set the "from" address is working correctly.

Usage

Sending plain text only

use SilverStripe\Control\Email\Email;

$email = Email::create($from, $to, $subject, $body);
$email->sendPlain();

Sending combined HTML and plain text

By default, emails are sent in both HTML and Plaintext format. A plaintext representation is automatically generated from the system by stripping HTML markup, or transforming it where possible (e.g. <strong>text</strong> is converted to *text*).

You can also specify plain text and HTML content separately if you don't want the plain text to be automatically generated from HTML

use SilverStripe\Control\Email\Email;

$email = Email::create('from@mydomain.com', 'to@example.com', 'My subject');
$email->html('<p>My HTML email content</p>');
$email->text('My plain text email content');
$email->send();

The default HTML template for emails is vendor/silverstripe/framework/templates/SilverStripe/Control/Email/Email.ss. To customise this template, first copy it to <project-root>/themes/<my-theme>/SilverStripe/Control/Email/Email.ss. Alternatively, copy it to a different location and use setHTMLTemplate when you create the Email instance. Note - by default the $EmailContent variable will escape HTML tags for security reasons. If you feel confident allowing this variable to be rendered as HTML, then update your custom email template to $EmailContent.RAW

Templates

HTML emails can use custom templates using the same template language as your website template. You can also pass the email object additional information using the setData and addData methods.

Calling setData() or addData() once or more will cause the email to be rendered using Silverstripe templates. This will override any email content set directly via methods such as setBody(), html(), or text().

<%-- app/templates/Email/MyCustomEmail.ss --%>
<h1>Hi $Member.FirstName</h1>
<p>You can go to $Link.</p>

The PHP Logic..

use SilverStripe\Control\Email\Email;
use SilverStripe\Security\Security;

$email = Email::create()
    ->setHTMLTemplate('Email\\MyCustomEmail')
    ->setData([
        'Member' => Security::getCurrentUser(),
        'Link' => $link,
    ])
    ->from($from)
    ->to($to)
    ->subject($subject);

$email->send();

As we've added a new template file (MyCustomEmail) make sure you clear the Silverstripe CMS cache for your changes to take affect.

Custom plain templates

By default Silverstripe CMS will generate a plain text representation of the email from the HTML body. However if you'd like to specify your own own plaintext version/template you can use $email->setPlainTemplate() to render a custom view of the plain email:

use SilverStripe\Control\Email\Email;

$email = Email::create($from, $to, $subject, $body);
$email->setPlainTemplate('MyPlanTemplate');
$email->send();

Administrator emails

You can set the default sender address of emails through the Email.admin_email configuration setting.

# app/_config/app.yml
SilverStripe\Control\Email\Email:
  admin_email: support@example.com

To add a display name, set admin_email as follow.

SilverStripe\Control\Email\Email:
  admin_email:
    support@example.com: 'Support team'

Adding display names and sending to multiple recipients

use SilverStripe\Control\Email\Email;

$from = [
  'from@mysite.exmaple.com' => 'Friendly business',
];
$to = [
  'person.a@customer.example.com' => 'Person A',
  'person.b@customer.example.com' => 'Person B',
  'person.c@customer.example.com',
]
$email = Email::create($from, $to, $subject, $body);

Remember, setting a from address that doesn't come from your domain (such as the users email) will likely see your email marked as spam. If you want to send from another address think about using the setReplyTo method.

You will also have to remove the SS_SEND_ALL_EMAILS_FROM environment variable if it is present.

If you need greater control over this email address, for instance if are running the subsites modules, you can implement the SilverStripe\Control\Email\Email::updateDefaultFrom() extension hook.

Redirecting emails

There are several other configuration settings to manipulate the email server.

  • SilverStripe\Control\Email\Email.send_all_emails_to will redirect all emails sent to the given address. All recipients will be removed (including CC and BCC addresses). This is useful for testing and staging servers where you do not wish to send emails out. For debugging the original addresses are added as X-Original-* headers on the email.
  • SilverStripe\Control\Email\Email.cc_all_emails_to and SilverStripe\Control\Email\Email.bcc_all_emails_to will add an additional recipient in the BCC / CC header. These are good for monitoring system-generated correspondence on the live systems.

Configuration of those properties looks like the following:

// app/_config.php
use SilverStripe\Control\Director;
use SilverStripe\Control\Email\Email;
use SilverStripe\Core\Config\Config;

if (Director::isLive()) {
    Config::modify()->set(Email::class, 'bcc_all_emails_to', 'client@example.com');
} else {
    Config::modify()->set(Email::class, 'send_all_emails_to', 'developer@example.com');
}

Setting custom "Reply To" email address

For email messages that should have an email address which is replied to that actually differs from the original "from" email, do the following. This is encouraged especially when the domain responsible for sending the message isn't necessarily the same which should be used for return correspondence and should help prevent your message from being marked as spam.

use SilverStripe\Control\Email\Email;

$email = Email::create($from, $to, $subject, $body);
$email->replyTo('reply@example.com');

Catching email send failure exceptions

If you wish to handle email send failures then you can wrap $email->send() with a try/catch block that catches the Symfony Mailer TransportExceptionInterface.

You might get a Symfony Mailer RfcComplianceException when instantiating the Email object if the email address you're trying to send to or from is invalid. In some cases you'll want to catch and handle that exception as well.

use SilverStripe\Control\Email\Email;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;

$email = Email::create('from@example.com', 'to@example.com', 'My subject');
$email->text('My plain text email content');
try {
    $email->send();
} catch (TransportExceptionInterface $e) {
    // handle exception
}

For more information, refer to handling sending failures in the symfony/mailer docs.

Advanced customisation

Silverstripe Email is built on top of symfony/mailer. For advanced customisation information refer to the symfony/mailer docs