wieni / wmmailable
A modern, plugin-based API for sending mails in Drupal 8.
Installs: 11 111
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 7
Forks: 1
Open Issues: 5
Type:drupal-module
Requires
- php: >=7.1.0
- drupal/core: ^9.3 || ^10.0
- drupal/mailsystem: ^4.0
- tijsverkoyen/css-to-inline-styles: ^2.2
Requires (Dev)
- ergebnis/composer-normalize: ^2.0
- wieni/wmcodestyle: ^1.3
Suggests
- hampe/inky: to use the Foundation for Emails renderer
README
A modern, plugin-based API for sending mails in Drupal 8. Inspired by Laravel
Why?
- No 'modern' way to handle mails in Drupal 8: messing with
hook_mail
andhook_theme
does not really fit in the Wieni Drupal flow with wmmodel, wmcontroller, etc. - No clean, object-oriented API, e.g. to add CC / BCC-adresses you have to manually add headers
- Not intuitive, logic is scattered across multiple files, tends to get messy
Installation
This package requires PHP 7.1 and Drupal 8 or higher. It can be installed using Composer:
composer require wieni/wmmailable
How does it work?
Building mails
- Mails are annotated plugins
- Each class represents one mail
- Dependency injection is possible by implementing the
ContainerFactoryPluginInterface
(tutorial)
<?php namespace Drupal\wmcustom\Mail; /** * @Mailable( * id = "contact_form_submission", * template = "mail.contact-submission" * ) */ class ContactFormSubmission extends MailableBase { public function build(array $parameters): MailableInterface; }
- It is possible to take over other module's mails at the time of sending. To do this, change the
id
andmodule
properties. The original mail parameters will be passed to thebuild
method. Example:
<?php namespace Drupal\wmcustom\Mail; /** * @Mailable( * id = "register_no_approval_required", * module = "user", * template = "mail.account-confirmation" * ) */ class AccountConfirmationMail extends MailableBase { public function build(array $parameters): MailableInterface { $parameters['oneTimeLoginUrl'] = user_pass_reset_url($parameters['account']); {...} } }
Theming mails
-
Mail templates should be stored in a theme. This theme can be set in the
theme
value of thewmmailable.settings
config, with the default theme as a fallback. -
The location of the template within the theme is also configurable:
- the default location is in the
mail
subfolder, with the id with dashes instead of underscores as template name. - a custom location can be set in the annotation, in the form of a path relative to the theme, with filename but without extension. Dots can be used as directory seperator.
- the default location is in the
-
The mail formatter determines how mails are rendered. Thanks to the mailsystem module, we can change the mail formatter separately from the mail sender. This module provides 3 formatters. The formatters as listed here are incremental: they all contain the features listed in the previous formatters.
- Mailable - Plain: the most basic mail formatter. Depending on the
passed
Content-Type
header, this formatter will output HTML or plain text mails. - Mailable - With inline styles: allows you to attach
asset libraries to mails by
passing them to
MailableInterface::addLibrary
or an array of asset libraries toMailableInterface::setLibraries
. - Mailable - Foundation for Emails: allows you to compose mails using
the Inky templating language.
To use this formatter, you need to have the
thampe/inky
package installed.
- Mailable - Plain: the most basic mail formatter. Depending on the
passed
Sending mails
- Mails are sent through the
Mailer
service - Two standard
Mailer
implementations are provided:mailable.mailer.direct
andmailable.mailer.queued
- The active implementation can be changed in the
mailable.settings.yml
config
<?php namespace Drupal\wmcustom\Form; use Drupal\wmmailable\Mailer\MailerInterface; class ContactForm extends FormBase { /** @var MailerInterface */ protected $mailer; public function __construct( MailerInterface $mailer ) { $this->mailer = $mailer; } public function submitForm(array &$form, FormStateInterface $formState) { $mail = $this->mailer->create('contact_form_submission') ->setRecepients(['Wieni <info@wieni.be>', 'dieter@wieni.be']) ->addBcc('sophie@wieni.be') ->setParameters( compact('domain', 'firstName', 'lastName', 'email', 'question') ); $this->mailer->send($mail); } public static function create(ContainerInterface $container) { return new static( $container->get('mailable.mailer') ); } }
Logging sent mails
- When enabled, this wil log all outgoing mails - also those that aren't composed through this module.
- To enable, configure the mailsystem module to use Mailable - Logger as the mail sender.
- To view logged mails, go to
/admin/reports/sent-mails
or follow the menu link at Reports > Sent mails.
Hooks and events
- Two hooks are provided,
hook_mailable_alter
andhook_mailable_{module}_{key}_alter
. These hooks are called after thesend
method is called on the mailable, but before the mail is sent.
<?php function wmcustom_mailable_alter(MailableInterface $mail) { $mail->setHeader('X-SES-SOURCE-ARN', '<...>'); }
- Two events are provided, equivalent to the hooks:
<?php use Drupal\wmmailable\Event\MailableAlterEvent; use Drupal\wmmailable\WmmailableEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class MailableAlterSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { $events[WmmailableEvents::MAILABLE_ALTER][] = 'onMailAlter'; return $events; } public function onMailAlter(MailableAlterEvent $event) { $mailable = $event->getMailable(); $mailable->setSubject("Here's a better subject."); } }
Changelog
All notable changes to this project will be documented in the CHANGELOG file.
Security
If you discover any security-related issues, please email security@wieni.be instead of using the issue tracker.
License
Distributed under the MIT License. See the LICENSE file for more information.