Create new mailer service based on symfony

Created on 8 August 2023, over 1 year ago

Problem/Motivation

Part of stage 2 of 🌱 [META] Adopt the symfony mailer component Needs review . Create a new API with direct access to all the power of Symfony Mailer. Enhances the symfony code with integration into Drupal mechanisms, including theme/template/render, multi-language, CSS libraries, configuration, plug-ins, hooks, and logging.

Proposed resolution

1) New service 'mailer'
Thin wrapper on top of Symfony\Component\Mailer\Mailer

  • Class Mailer implements MailerInterface
  • Function send(EmailInterface $email) - similar to base Mailer class
  • Convenience factory function create(string $type, string $sub_type, array $params); that returns EmailInterface
  • Function mail(string $type, string $sub_type, array $params); that creates and sends, delegating all building to an "Email Builder" - similar to MailManagerInterface

Main responsibilities:

  • Switches render context to avoid leaking into current request
  • Switches language
  • Switches theme
  • Switches account (for access control and correct rendering of entities)
  • Calls events/processors - see below.
  • Renders using a template (normal way, from theme with suggestions)

2) New class Email implements EmailInterface
This would enhance the symfony base class with some new fields:

  • type/sub-type used by events/processors, templates etc
  • params array for use by hooks, templates
  • langcode
  • transport (allows to use a different transport for different types of mail)
  • library/theme (used to attach CSS)

We need to make some changes to the base class. For example the base function subject(string $subject) would force translation too soon, before the right language has been selected.

3) Callbacks: events and processors
The email building pipeline has the following phases: build, render, post-render, send, post-send. The ones in italics are done by the Mailer, the others are done by code that builds/alters emails. For the latter case, there are two options:

  • Handle an event (there is one event for each phase)
  • Write an email processor class implementing EmailProcessorInterface, which has a function for each phase

All the events and functions have a single argument/member of type EmailInterface.

4) Email Builder
Implemented by a module to send emails (resembling the old hook_mail() callback). This is optional and modules can also build mails directly.

  • New plug-in @EmailBuilder with classes implementing EmailProcessorInterface
  • Manager EmailBuilderManager implementing EmailBuilderManagerInterface

Questions:
1) Should we create a new module mailer, initially experimental?

  • Advantage: it's important that we can make non-BC changes during the development.
  • Disadvantage: we probably don't want a module in the end, so we'd have to later remove it which presumably changes namespaces (presumably at the point the new code becomes stable).

2) Should the new class Email extend the base symfony one, or decorate it (meaning have a class variable $inner containing the base class)?

  • Advantage extend: we can pass our class everywhere where the base class is expected.
  • Advantage decorate: we can make a clean start, renaming/removing functions or changing their parameters.

Remaining tasks

User interface changes

None

API changes

See proposed resolution

Data model changes

None

Release notes snippet

Feature request
Status

Active

Version

11.0 🔥

Component
Mail 

Last updated 8 days ago

No maintainer
Created by

🇬🇧United Kingdom adamps

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024