wieni/wmmailable

A modern, plugin-based API for sending mails in Drupal 8.

Installs: 11 519

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 8

Forks: 1

Open Issues: 5

Type:drupal-module

2.4.0 2023-09-12 12:37 UTC

README

Latest Stable Version Total Downloads License

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 and hook_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 and module properties. The original mail parameters will be passed to the build 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 the wmmailable.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 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 to MailableInterface::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.

Sending mails

  • Mails are sent through the Mailer service
  • Two standard Mailer implementations are provided: mailable.mailer.direct and mailable.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 and hook_mailable_{module}_{key}_alter. These hooks are called after the send 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.