How to Send Emails in Symfony with Examples

Symfony is another popular PHP framework and a great toolset for web development. Its mailer feature is based on the Swift Mailer library, same as in Laravel so the syntax is similar.

It is easy to integrate it with an external SMTP like Gmail as well as popular email providers like Mandrill, SendGrid, or Amazon SES.

In this post, we will review how to build an HTML email, embed images, attach files, test it with Mailtrap, and then send. This guide was created and tested on Symfony version 4.2 (please note that it significantly differs from previous ones).

We assume that you already work with Symfony and are acquainted with its main components and principles.

First email configurations in Symfony

Symfony mailer is based on Swift Mailer so you need to install it first. If you use Symfony Flex, the installation is very simple:

 composer require symfony/swiftmailer-bundle

If not, then follow instructions on GitHub.

The second step is to define the server. We always run all the experiments in the pre-production environment. So, we will start with testing our emails with Mailtrap fake SMTP server. Go to your project directory and set the MAILER_URL value in the .env file to the following:

MAILER_URL=smtp://smtp.mailtrap.io:2525?encryption=tls&auth_mode=login&username=1a2b3c4d5e6f7g&password=1a2b3c4d5e6f7g

Tip: you will find ready to use integration details in the Integrations section of the SMTP Setting tab in your Mailtrap inbox. It will already contain your credentials.

How to create an email in Symfony

To create an email in Symfony, we use Swift_Message objects. The main and the largest object is $message. It has many properties and supports HTML, attachments, media – all the additional attributes to compose a good looking and informative email.

Another important thing to remember is that the message and all its parts are MIME entities.

Let’s start creating a message from top to bottom, likely to an email client: set recipient, sender,  and a subject. Usually, we will make it with setSubject(), setTo(), and setFrom() methods. To include several recipients, use an array and to add recipients in copy, use setCc() or setBcc(). Also, you can set name headers with associative arrays:

// Create the message
$message = (new Swift_Message())
  // Add subject
  ->setSubject('Here should be a subject')

  //Put the From address 
->setFrom(['support@mailtrap.io'])

  // Include several To addresses
 ->setTo(['newuser@example.com' => 'New Mailtrap user'])
->setCc([
'support@mailtrap.io',
‘product@mailtrap.io’ => ‘Product manager’
]);

For more details and alternatives, refer to the corresponding section in the Swift Mailer documentation.

Adding HTML content

In Swift Mailer, you need to define which type of content you are going to add to your message body. It can be text/html, text/plain, or both.

Tip: wherever possible, include a plain text version for the HTML content. If for some reason the HTML part won’t be rendered, your recipient will still be able to understand the content of your message.

For this purpose, use setBody() method and addPart() for the alternative. For example:

$message->setBody(<p>'Welcome to Maitrap!</p>
Now your test emails will be <i>safe</i>', 'text/html');
$message->addPart('Welcome to Mailtrap, now your test emails will be safe', 'text/plain');

How to embed images

Even if you are sending transactional emails, most probably you will need to include at least your company’s logo. In Symfony, it is simple and you have several options as well.

Swift Mailer lets you embed your image directly, without any additional manipulations. Use  Swift_EmbeddedFile::fromPath().method for this purpose. It is very similar to inserting an image to the body of your message in many email clients. So, you should have an image file saved locally on your computer or you can even add an image hosted on some website. For the later, allow_url_fopenshould be open in your PHP installation (read more about it in the PHP manual).

// Create the message, you can add the subject right here if you like
$message = new Swift_Message('The subject should be here');

// Set the body
$message->setBody(
'<html>' .
' <body>' .
'Here is our new logo <img src="'
     $message->embed(Swift_Image::fromPath('newlogo.png')) .
   '" alt="new logo" />' .
' Let us know how you like it' .
' </body>' .
'</html>',
  'text/html' // don’t forget to mark the content type
);

Embedding an image from a URL looks similar:

$message->setBody(
'<html>' .
' <body>' .
'  Here is our new logo <img src="' .
     $message->embed(Swift_Image::fromPath('https://mailtrap.io/newlogo.png')) .
   '" alt="Image" />' .
'  Let us know how you like it' .
' </body>' .
'</html>',
  'text/html'
);

Alternatively, you can embed the image as a CID attachment:

$cid = $message->embed(Swift_Image::fromPath('newlogo.png'));

$message->setBody(
'<html>' .
' <body>' .
'  Here is our new logo <img src="' . $cid . '" alt="Image" />' .
'  Let us know how you like it' .
' </body>' .
'</html>',
  'text/html'
);

Here is another nice option – Swift_Image() method. As per Swift Mailer documentation, “Swift_Image and Swift_EmbeddedFile are just aliases of one another. Swift_Image exists for semantic purposes.”

Anyway, it allows embedding dynamic content, for instance, images created via PHP GD.

// Create your file contents
$img_data = create_my_image_data();

// Create the message
$message = new Swift_Message('Dynamic Picture');

// Set the body
$message->setBody(
'<html>' .
' <body>' .
'  Here is a new picture <img src="' . // Embed the file
     $message->embed(new Swift_Image($img_data, 'image.jpg', 'image/jpeg')) .
   '" alt="Image" />' .
'  Anything else?' .
' </body>' .
'</html>',
  'text/html' 
);

Twig templates

Another great alternative for adding HTML content to your email is Twig templates. In Symfony, Twig is the templating format used by default. Template creation deserves a separate article so we won’t go deeper here. You can find the detailed guide in Symfony documentation.

To handle a template in your message, use renderView() method in setBody(). Tip: it’s recommended to store the application templates in the templates/ folder in the project’s root.

 
  ->setBody(
            $this->renderView(
                // templates/emails/newuser.html.twig
                'emails/newuser.html.twig',
                ['name' => $name]
            ),
            'text/html'
        )
        ->addPart(
            $this->renderView(
                'emails/newuser.txt.twig',
                ['name' => $name]
            ),
            'text/plain'
        )
    ;

How to include attachments

Attaching files works almost the same as embedding images. You also can attach files saved locally, from URLs, or add dynamic content. The difference is that you use Swift_Attachment class here and its attach() method.

Tip: The recipient will download the file with the same name you’ve specified. Double-check it when adding an attachment! To rename the file right in the script, use ->setFilename() method.

// For the regular file types like docs, spreadsheets, or images, you can go without the content type 
$message->attach(Swift_Attachment::fromPath('/path/to/image.jpg'));

// attach a file from a URL 
$message->attach(Swift_Attachment::fromPath('https://mailtrap.io/newlogo.jpg'));
// Create the attachment and rename it
$message->attach(
  Swift_Attachment::fromPath('/path/to/newlogo.jpg')->setFilename('logofinal.jpg')
);
// now let’s add a pdf file created via GD and set its content type
$data = create_confirmation_pdf_data();
$attachment = new Swift_Attachment($data, 'confirmation.pdf', 'application/pdf');
$message->attach($attachment);

Sending a message in Symfony

Above we have defined the subject of our message, its recipients, and the content. Looks like the email is ready to be sent. Let’s test if everything works as intended with Mailtrap first. We have already set the MAILER_URL value in the .env file, so we simply use the Mailer class to send the message:

   $mailer->send($message);

Let’s compose the whole message and send it. In this example we use both HTML and plain text parts, embed an image and attach a PDF file:

public function index($name, \Swift_Mailer $mailer)
{

 $message = (new Swift_Message())
 ->setSubject('Here should be a subject')
->setFrom(['support@example.com'])
 ->setTo(['newuser@example.com' => 'New Mailtrap user'])
->setCc([
'product@example.com' => 'Product manager'
]);
$message->setBody(
'<html>' .
' <body>' .
'  <img src="' .
     $message->embed(Swift_Image::fromPath('image.png')) .
   '" alt="Image" />' .
'  <p>Welcome to Mailtrap!</p>’.
‘Now your test emails will be <i>safe</i>’ .
' </body>' .
'</html>',
  'text/html'
);
$message->addPart('Welcome to Mailtrap, now your test emails will be safe', 'text/plain');
$message->attach(Swift_Attachment::fromPath('/path/to/confirmation.pdf'));
$mailer->send($message);

If we did everything right, the message will be trapped in the Mailtrap virtual inbox immediately:

Email built with Symfony - test and preview in Mailtrap

So, it works. In the HTML tab, we can see how the message is rendered. It demonstrates the subject, headers, image, the text, and the attachment.

Also, you can check other tabs to get more detailed information on the HTML source, message details, or spam score:

Email built with Symfony - test and raw in Mailtrap

Once we have verified that the result meets our expectations, we can move on to production options.

Sending a message via SMTP server

To configure an SMTP server, change MAILER_URL value in the .env file. For example, for Gmail, it will be the following:

MAILER_URL=smtp://smtp.gmail.com:587?encryption=tls&amp;username=USERNAME&amp;password=PASSWORD

Here you put your Gmail account username and password. But if the 2-Step-Verification is set for this account, you need to use the App password and let less secure apps access your account.

In a similar way, you can configure sending via any email service, which provides SMTP.

Cloud services for email sending

Cloud mailing services are another popular option to use, without a need to set up own infrastructure. It also won’t take much efforts to configure sending via your Symfony app.  Update the value of MAILER_URL in the .env file, same as we did before. You will need to get the hostname and credentials from your provider. For example, for Amazon SES, the configuration will look as follows:

MAILER_URL=smtp://email-smtp.us-east-1.amazonaws.com:587?encryption=tls&amp;username=YOUR_SES_USERNAME&amp;password=YOUR_SES_PASSWORD

Swift Mailer is one of the most popular PHP libraries so it will be easy to find examples of integration with various services.