Skip to content

Commit

Permalink
DOC Updates for symfony/mailer
Browse files Browse the repository at this point in the history
  • Loading branch information
emteknetnz committed Oct 3, 2022
1 parent 8382603 commit bef809b
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 117 deletions.
186 changes: 70 additions & 116 deletions en/02_Developer_Guides/10_Email/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,101 +6,81 @@ icon: envelope-open

# Email

Creating and sending email in Silverstripe CMS is done through the [Email](api:SilverStripe\Control\Email\Email) and [Mailer](api:SilverStripe\Control\Email\Mailer) classes. This document covers how to create an `Email` instance, customise it with a HTML template, then send it through a custom `Mailer`.
Creating and sending email in Silverstripe CMS is done using the [Email](api:SilverStripe\Control\Email\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 the [SwiftMailer](http://swiftmailer.org/) PHP library which comes with an extensive list of "transports" for sending mail via different services.
Silverstripe CMS provides an API over the top of [symfony/mailer](https://symfony.com/doc/current/mailer.html) which comes with an extensive list of "transports" for sending mail via different services such as SMTP, Gmail, and Amazon SES.

For legacy reasons, Silverstripe CMS defaults to using the built-in PHP `mail()` command via a deprecated class `Swift_MailTransport`. However, using this layer is less secure and is strongly discouraged.
Email configuration is done using Symfony's [DSN](https://symfony.com/doc/current/mailer.html#transport-setup) 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.

It's highly recommended you upgrade to a more robust transport for additional security. The Sendmail transport is the most common one. The `sendmail` binary is widely available across most Linux/Unix servers.
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](#dsn-sendmail) as part of the `DSN`.

You can use any of the Transport classes provided natively by SwiftMailer. There are also countless PHP libraries offering custom Transports to integrate with third party mailing service:
- read the [SwiftMailer Transport Types documentation](https://swiftmailer.symfony.com/docs/sending.html#transport-types) for a full list of native Transport
- search [Packagist for SwiftMailer Transport](https://packagist.org/?query=SwiftMailer+Transport) to discover additional third party integrations
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](https://symfony.com/doc/current/mailer.html#using-a-3rd-party-transport).
[hint]
The format for the DSN is exactly as defined in the symfony docs linked above. Some common examples are listed below.
[/hint]

To swap out the transport used by the `Mailer`, create a file `app/_config/email.yml`
To set the DSN string in an environment variable (recommended):

To use a `sendmail` binary:

```yml
---
Name: myemailconfig
After:
- '#emailconfig'
---
SilverStripe\Core\Injector\Injector:
Swift_Transport:
class: Swift_SendmailTransport
**.env**
```
MAILER_DSN="<my-dsn>"
```

To use SMTP:
To set the DSN string in project yml:

**app/_config/myemail.yml**
```yml
---
Name: myemailconfig
After:
- '#emailconfig'
Name: mailer-dsn-config
After: '*'
---
SilverStripe\Core\Injector\Injector:
Swift_Transport:
class: Swift_SmtpTransport
properties:
Host: smtp.host.com
Port: <port>
Encryption: tls
calls:
Username: [ setUsername, ['`APP_SMTP_USERNAME`'] ]
Password: [ setPassword, ['`APP_SMTP_PASSWORD`'] ]
AuthMode: [ setAuthMode, ['login'] ]
Symfony\Component\Mailer\Transport\TransportInterface:
constructor:
dsn: '<my-dsn>'
```
Note the usage of backticks to designate environment variables for the credentials - ensure you set these in your `.env` file or in your webserver configuration.
The configuration priority order is as follows, from highest to lowest:
- Project yml containing `After: '*'`
- The `MAILER_DSN` environment variable
- The default silverstripe DSN of `sendmail://default` which will use `/usr/sbin/sendmail -bs`

### Common DSN strings

### Mailer Configuration for dev environments
#### To configure SMTP {#dsn-smtp}

You may wish to use a different mailer configuration in your development environment. This can be used to suppress outgoing messages or to capture them for debugging purposes in a service like [MailCatcher](https://mailcatcher.me/).
**.env**
```
MAILER_DSN="smtp://user:pass@smtp.example.com:1234"
```
You can suppress all emails by using the [`Swift_Transport_NullTransport`](https://github.com/swiftmailer/swiftmailer/blob/master/lib/classes/Swift/Transport/NullTransport.php).
#### To configure a different sendmail binary and command {#dsn-sendmail}
```yml
---
Name: mydevemailconfig
After:
- '#emailconfig'
Only:
environment: dev
---
SilverStripe\Core\Injector\Injector:
Swift_Transport:
class: Swift_Transport_NullTransport
**.env**
```
MAILER_DSN="sendmail://default?command=/path/to/mysendmailbinary%20-t"
```
If you're using MailCatcher, or a similar tool, you can tell `Swift_SendmailTransport` to use a different binary.
#### To suppress all emails {#dsn-null}
```yml
---
Name: mydevemailconfig
After:
- '#emailconfig'
Only:
environment: dev
---
SilverStripe\Core\Injector\Injector:
Swift_Transport:
class: Swift_SendmailTransport
constructor:
0: '/usr/bin/env catchmail -t'
**.env**
```
MAILER_DSN="null://default"
```
Read more about other available DSN strings in [the symfony documentation](https://symfony.com/doc/current/mailer.html#using-a-3rd-party-transport)
### 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`:
```php
$email = new Email('no-reply@mydomain.com', 'myuser@gmail.com', 'My test subject', 'My email body text');
use SilverStripe\Control\Email\Email;
$email = new Email($from, $to, $subject, $body);
$email->send();
```

Expand All @@ -110,7 +90,6 @@ Using the code snippet above also tests that the ability to set the "from" addre

### Sending plain text only


```php
use SilverStripe\Control\Email\Email;

Expand All @@ -124,27 +103,30 @@ By default, emails are sent in both HTML and Plaintext format. A plaintext repre
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

```php
$email = new Email($from, $to, $subject, $body);
use SilverStripe\Control\Email\Email;

$email = new Email('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();
```

[info]
The default HTML template for emails is named `GenericEmail` and is located in `vendor/silverstripe/framework/templates/SilverStripe/Email/`.
To customise this template, copy it to the `app/templates/Email/` folder or use `setHTMLTemplate` when you create the
`Email` instance.
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`
[/info]


### 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.

**app/templates/Email/MyCustomEmail.ss**


```ss
<h1>Hi $Member.FirstName</h1>
<p>You can go to $Link.</p>
Expand All @@ -153,15 +135,18 @@ email object additional information using the `setData` and `addData` methods.
The PHP Logic..

```php
$email = SilverStripe\Control\Email\Email::create()

use SilverStripe\Control\Email\Email;

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

if ($email->send()) {
//email sent successfully
Expand All @@ -170,7 +155,6 @@ if ($email->send()) {
}

```

[alert]
As we've added a new template file (`MyCustomEmail`) make sure you clear the Silverstripe CMS cache for your changes to
take affect.
Expand All @@ -183,7 +167,9 @@ to specify your own own plaintext version/template you can use `$email->setPlain
the plain email:

```php
$email = new SilverStripe\Control\Email\Email();
use SilverStripe\Control\Email\Email;

$email = new Email($from, $to, $subject, $body);
$email->setPlainTemplate('MyPlanTemplate');
$this->send();
```
Expand All @@ -193,8 +179,6 @@ $this->send();
You can set the default sender address of emails through the `Email.admin_email` [configuration setting](/developer_guides/configuration).

**app/_config/app.yml**


```yaml
SilverStripe\Control\Email\Email:
admin_email: support@example.com
Expand All @@ -221,20 +205,20 @@ If you need greater control over this email address, for instance if are running

There are several other [configuration settings](/developer_guides/configuration) to manipulate the email server.

* `SilverStripe\Control\Email\Email.send_all_emails_to` will redirect all emails sent to the given address.
* `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
* `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**

```php
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 {
Expand All @@ -250,45 +234,15 @@ necessarily the same which should be used for return correspondence and should h
marked as spam.

```php
$email = new Email(..);
$email->setReplyTo('reply@example.com');
```

### Setting Custom Headers

For email headers which do not have getters or setters (like setTo(), setFrom()) you can manipulate the underlying
`Swift_Message` that we provide a wrapper for.


```php
$email = new Email(...);
$email->getSwiftMessage()->getHeaders()->addTextHeader('HeaderName', 'HeaderValue');
```

[info]
See this [Wikipedia](http://en.wikipedia.org/wiki/E-mail#Message_header) entry for a list of header names.
[/info]

## Disabling Emails

If required, you can also disable email sending entirely. This is useful for testing and staging servers where
you do not wish to send emails out.
use SilverStripe\Control\Email\Email;
```yaml
---
Name: myemailconfig
Only:
Environment: dev
---
SilverStripe\Core\Injector\Injector:
Swift_Transport:
class: Swift_NullTransport
$email = new Email($from, $to, $subject, $body);
$email->replyTo('reply@example.com');
```

## SwiftMailer Documentation

For further information on SwiftMailer, consult their docs: http://swiftmailer.org/docs/introduction.html
## Advanced customisation

Silverstripe Email is built on top of [symfony/mailer](https://github.com/symfony/mailer). For advanced customisation information refer to the [symfony/mailer docs](https://symfony.com/doc/current/mailer.html)

## API Documentation

Expand Down
41 changes: 40 additions & 1 deletion en/04_Changelogs/5.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ title: 5.0.0 (unreleased)
- [API changes](#api-changes)
- [Removed API (by module, alphabetically)](#api-removed)
- [General changes](#api-general)
- [Email](#api-email)
- [ORM](#api-orm)
- [Dependency changes](#dependency-changes)
- [Features and enhancements](#features-and-enhancements)
- [Other features](#other-features)
- [Bugfixes](#bugfixes)

## API changes
## API changes {#api-changes}

This is a major release and as a result there are a number of breaking API changes. For a full list of these see [upgrading your project](/upgrading/upgrading_your_project). Some specific details about a few of them are below.

Expand Down Expand Up @@ -60,6 +61,29 @@ This is a major release and as a result there are a number of breaking API chang
- `SilverStripe\ORM\Connect\Query`
- Removed `SilverStripe\ORM\DataList::getGenerator()` (use `getIterator()` instead)
- Removed the `SilverStripe\ORM\Map_Iterator` class. `SilverStripe\ORM\Map` now uses a generator instead.
- Removed various API related to SwiftMailer
- Removed the following classes and interfaces
- `SilverStripe\Control\Email\Mailer`
- `SwiftMailer`
- `SwiftPlugin`
- Removed the following methods from `SilverStripe\Control\Email\Email`, in most instances these have been replaced with equivalent functionality:
- `debug()`
- `hasPlainPart()`
- `invalidateBody()`
- `findPlainPart()`
- `generatePlainPartFromBody()`
- `getBCC()`
- `getCC()`
- `getFailedRecipients()`
- `getFrom()`
- `getReturnPath()`
- `getSender()`
- `getSwiftMessage()`
- `getTo()`
- `setSwiftMessage()`
- `setFailedRecipients()`
- `BaseURL()`
- `IsEmail()`
- Removed deprecated method `SilverStripe\Core\BaseKernel::sessionEnvironment()`
- Removed deprecated method `SilverStripe\Core\Extensible::constructExtensions()`

Expand Down Expand Up @@ -100,6 +124,19 @@ This is a major release and as a result there are a number of breaking API chang
- `SilverStripe\Core\Extensible::invokeWithExtensions()` and `SilverStripe\Core\Extensible::extend()` now use the splat operator instead of having a concrete number of possible arguments.
- The constructor for `SilverStripe\Versioned\Versioned` now explicitly only accepts mode as a single argument.

### Email {#api-email}

- Email was sent in CMS 4 using [SwiftMailer](https://swiftmailer.symfony.com/docs/introduction.html), which has since [gone End Of Life](https://symfony.com/blog/the-end-of-swiftmailer). In CMS 5 this has been replaced with [symfony/mailer](https://symfony.com/doc/current/mailer.html). `symfony/mailer` is the currently maintained email package from Symfony. It's a more flexible email system that allows easier integration with third-party email providers.
- In CMS 4 the `SilverStripe\Control\Email\Email` class subclassed `SilverStripe\View\ViewableData`. In CMS 5 it now subclasses `Symfony\Component\Mime\Email`.
- `MailTransport`, which used the php native `mail()` function, is no longer officially supported in CMS 5. This is because [Symfony considers `mail()` to be insecure](https://github.com/swiftmailer/swiftmailer/issues/866#issuecomment-289291228).
- If your site has a custom email configuration e.g. SMTP configuration, this will need to be updated, as the configuration has changed from Silverstripe yml to a much more flexible and standardised [DSN string](https://symfony.com/doc/current/mailer.html#transport-setup). See [the email documentation](/developer_guides/email/) for more details.
- The following API changes also were made:
- Changed return types on the following methods in `SilverStripe\Control\Email\Email`
- `send()`
- `sendPlain()`
- Changed visibility on the following methods to `private` in `SilverStripe\Control\Email\Email`
- `mergeConfiguredEmails()`

### ORM {#api-orm}

- Prior to 5.0.0, when using `SQLSelect::setFrom()` or `SQLSelect::create('*', $from)` to set table or subselect definitions,
Expand All @@ -121,6 +158,7 @@ their aliases (applied by setting a string key for the array) were being ignored

## Dependency changes

- swiftmailer/swiftmailer has been removed and replaced with symfony/mailer
- Various Symfony dependencies have been upgraded from 4.x to 6.x. A small number of code changes were made in silverstripe/framework to work with the symfony 6.x dependencies.
- silverstripe/graphql v3 is no longer supported. It is recommended that you ensure you are using graphl v4 in your Silverstripe CMS 4 project before upgrading to Silverstripe CMS 5. There is [documentation for the upgrade process here](https://docs.silverstripe.org/en/4/upgrading/upgrading_to_graphql_4/).
- PHPUnit 5.7 is no longer supported. It is recommended that you ensure your tests are running with PHPUnit 9 in your Silverstripe CMS 4 project before upgrading to Silverstripe CMS 5. There is [documentation for the upgrade process here](https://docs.silverstripe.org/en/4/upgrading/phpunit9/).
Expand All @@ -146,6 +184,7 @@ This release includes a number of bug fixes to improve a broad range of areas. C
## Environment variable changes

- `SS_MANIFESTCACHE` can no longer use the now removed symfony/cache 4.x "Simple" cache classes e.g. `Symfony\Component\Cache\Simple\PhpFilesCache`. Instead use the corresponding "Adapter" class e.g. `Symfony\Component\Cache\Adapter\PhpFilesAdapter`.
- `APP_SMTP_USERNAME` and `APP_SMTP_PASSWORD` have been removed. Use a `MAILER_DSN` environment variable instead to configure SMTP email (see [the email documentation](/developer_guides/email/) for more details).

<!--- Changes below this line will be automatically regenerated -->

Expand Down

0 comments on commit bef809b

Please sign in to comment.