Email attachments are not included anymore after Symfony Mailer update

woensdag 11 juni 2025 - 299 woorden, 2 min read

After I updated the Symfony Mailer contrib module to version 1.6.1, all emails attachments were missing of the emails being sent.

Since version 1.6.0 there is a new feature for access checking on attachments to improve security on what files may be included as attachments of emails being sent. As described in this changelog

Default access set by AttachmentAccessEmailAdjuster. Allows public files, temporary content (via Attachment::fromData()) and anything that the webserver allows access to using http/https.

This means that for example private files are not attached anymore to emails. As also described in the changelog:

Custom code is needed to attach any other content. Obviously this creates extra work but it avoids the attackers emailing themselves private files such as settings.php or webserver log/config.

In one of the Drupal project I maintain, there are a lot of emails being sent with attachments which are configured as private files in the Drupal private:// directory. After updating the Symfony Mailer module, all attachments were missing which caused a major issue for that project.

The snippet below is part of the solution I’ve applied in the custom code where the emails are being sent using the EmailFactory class:

/** @var \Drupal\symfony_mailer\Email $email */
$email = $this->emailFactory->newTypedEmail($email_params['type'], $email_params['sub_type'], $email_params);
if ($email_params['attachments']) {
  /** @var File $attachment */
  foreach ($email_params['attachments'] as $attachment) {
	/** @var \Drupal\symfony_mailer\Attachment $at */
	$at = Attachment::fromPath($attachment->getFileUri(), $attachment->getFilename());
	if($at->hasAccess() === false) {
	  // We don't have access to the attachment, so force allowed access here.
	  $at->setAccess(AccessResult::allowed());
	}
	$email->attach($at);
  }
}
$email->send();

All attachments are in the $emails_params['attachments'] array. All items are processed in a loop where an Attachment object is created. You can check the access on this object with hasAccess() and if false is returned, we change the access with setAccess(AccessResult::allowed()). Also mention / don’t forget the attachment object to $email before it’s being send.

Related Drupal issues:


Sebastian Hagens @Sebastix
I work as creative webdeveloper & tech consultant and care about digital freedoms. Follow me:
or visit my contact page