This course is still being released! Check back later for more chapters.

Get Notified About this Course!

We will send you messages regarding this course only
and nothing else, we promise.
You can unsubscribe anytime by emailing us at:
privacy@symfonycasts.com
Login to bookmark this video
08.

Attachments and Images

|

Share this awesome video!

|

Can we add an attachment to our email? Of course! Doing this manually is a complex and delicate process. Luckily, the Symfony Mailer makes it a cinch.

In the tutorial/ directory, you'll see a terms-of-service.pdf file. Move this into assets/, though it could live anywhere.

In TripController::show(), we need to get the path to this file. Add a new string $termsPath argument and with the #[Autowire] attribute and %kernel.project_dir%/assets/terms-of-service.pdf':

78 lines | src/Controller/TripController.php
// ... lines 1 - 20
final class TripController extends AbstractController
{
// ... lines 23 - 31
public function show(
// ... lines 33 - 38
#[Autowire('%kernel.project_dir%/assets/terms-of-service.pdf')]
string $termsPath,
): Response {
// ... lines 42 - 75
}
}

Cool, right?

Attachments

Down where we create the email, write ->attach and see what your IDE suggests. There are two methods: attach() and attachFromPath(). attach() is for adding the raw content of a file (as a string or stream). Since our attachment is a real file on our filesystem, use attachFromPath() and pass $termsPath then a friendly name like Terms of Service.pdf:

78 lines | src/Controller/TripController.php
// ... lines 1 - 20
final class TripController extends AbstractController
{
// ... lines 23 - 31
public function show(
// ... lines 33 - 40
): Response {
// ... lines 42 - 53
$email = (new TemplatedEmail())
// ... lines 55 - 57
->attachFromPath($termsPath, 'Terms of Service.pdf')
// ... lines 59 - 64
;
// ... lines 66 - 69
}
// ... lines 71 - 75
}
}

This will be the name of the file when it's downloaded. If the second argument isn't passed, it defaults to the file's name.

Attachment done. That was easy!

Embedding Images

Next, let's add the trip image to the booking confirmation email. But we don't want it as an attachment. We want it embedded in the HTML. There are two ways to do this: First, the standard web way: use an <img> tag with an absolute URL to the image hosted on your site. But, we're going to be clever and embed the image directly into the email. This is like an attachment, but isn't available for download Instead, you reference it in the HTML of your email.

First, like we did with our external CSS files, we need to make our images available in Twig. public/imgs/ contains our trip images and they're all named as <trip-slug.png>.

In config/packages/twig.yaml, add another paths entry: %kernel.project_dir%/public/imgs: images:

10 lines | config/packages/twig.yaml
twig:
// ... line 2
paths:
// ... line 4
'%kernel.project_dir%/public/imgs': images
// ... lines 6 - 10

Now we can access this directory in Twig with @images/. Close this file.

The email Variable

When you use Twig to render your emails, of course you have access to the variables passed to ->context() but there's also a secret variable available called email. This is an instance of WrappedTemplatedEmail and it gives you access to email-related things like the subject, return path, from, to, etc. The thing we're interested in is this image() method. This is what handles embedding images!

Let's use it!

In booking_confirmation.html.twig, below this <h1>, add an <img> tag with some classes: trip-image from our custom CSS file and float-center from Foundation.

For the src, write {{ email.image() }}, this is the method on that WrappedTemplatedEmail object. Inside, write '@images/%s.png'|format(trip.slug). Add an alt="{{ trip.name }}" and close the tag:

{% apply inky_to_html|inline_css(source('@styles/foundation-emails.css'), source('@styles/email.css')) %}
<container>
<row>
<columns>
// ... lines 5 - 6
<h1 class="trip-name">{{ trip.name }}</h1>
<img
class="trip-image float-center"
src="{{ email.image('@images/%s.png'|format(trip.slug)) }}"
alt="{{ trip.name }}">
</columns>
</row>
// ... lines 14 - 34
</container>
{% endapply %}

Image embedded! Let's check it!

Back in the app, book a trip... and check Mailtrap. Here's our email and... here's our image! We rock! It fits perfectly and even has some nice rounded corners.

Up here, in the top right, we see "Attachment (1)" - just like we expect. Click this and choose "Terms of Service.pdf" to download it. Open it up and... there's our PDF! Our space lawyers actually made this document fun - and it only cost us 500 credits/hour! Investor credits well spent!

Next, we're going to remove the need to manually set a from to each email by using events to add it globally.