Email helper


1Presentation

Helper for sending emails, with the option of sending simple plain text messages, or more complex messages (HTML and text format, attachments).

The \Temma\Utils\Email object provides two families of methods.

The static methods (simpleMail(), fullMail()) let you send an email quickly. They rely on PHP's native mail() function: they therefore require a local SMTP server (an MTA such as sendmail, Postfix or Exim) installed and configured on the machine.

The object-oriented methods (textMail(), mimeMail(), templatedMail()) are used via the dependency injection component and take advantage of the parameters configured in the etc/temma.php file: choosing an SMTP relay, disabling mailings, filtering allowed domains, adding carbon-copy recipients, and so on. If the transport is not configured, they too use the mail() function.

It is strongly recommended to use the object-oriented methods (rather than the static methods), as this allows you to configure mailings. For example, you can disable mailings when you deploy your site on a test server; or restrict mailings to some domains.

2Static methods

These methods send messages through PHP's native mail() function: they therefore require a local SMTP server (sendmail, Postfix, Exim…) installed and configured on the machine. Having no instance state, they take into account neither the x-email configuration nor a relay; for that, use the object-oriented methods.

2.1simpleMail()

This static method makes it easy to send an email with plain text content.

Method signature:

simpleMail(string $from, string|array $to, string $title='',
           string $message='', string|array $cc='',
           string|array $bcc='', ?string $envelopeSender=null) : void

Parameters:

  • $from: Sender of the message, in the form "address@domain" or "Name <address@domain>".
  • $to: Recipient of the message, in the form "address@domain" or "Name <address@domain>".
  • $title: Title of the message.
  • $message: Textual content of the message.
  • $cc: Recipient copied to the message, or list of recipients.
  • $bcc: Recipient in hidden copy, or list of recipients.
  • $envelopeSender: Sender address sent to sendmail.

Example:

use \Temma\Utils\Email as TµEmail;

// send a plain text message
TµEmail::simpleMail('luke@rebellion.org', 'vader@empire.com',
                    "I can't believe it", "You are my father?");

2.2fullMail()

This static method can be used to send plain text and/or HTML e-mails, with attachments if required.

Method signature:

fullMail(string $from, string|array $to, string $title='',
         string $html='', ?string $text=null, ?array $attachments=null,
         string|array $cc='', string|array $bcc='',
         ?string $unsubscribe=null, ?string $envelopeSender=null) : void

Parameters:

  • $from: Sender of the message, in the form "address@domain" or "Name <address@domain>".
  • $to: Recipient of the message, in the form "address@domain" or "Name <address@domain>".
  • $title: Title of the message.
  • $html: Message content in HTML format.
  • $text: Textual content of the message.
  • $attachments: List of attachments, each represented by an associative array containing the following keys:
    • filename: File name.
    • mimetype: MIME type of the file.
    • data: Binary content of the file.
  • $cc: Recipient copied to the message, or list of recipients.
  • $bcc: Recipient in hidden copy, or list of recipients.
  • $unsubscribe: Contents of SMTP List-Unsubscribe header.
  • $envelopeSender: Sender address sent to sendmail.

Example:

use \Temma\Utils\Email as TµEmail;

TµEmail::fullMail('vader@empire.com', "luke@rebellion.org",
                  "Hi kid", "<h1>Yep</h1><p>I'm your father</p>");

3Object-oriented methods

These methods require the object to be instantiated via the dependency injection component.

Unlike the static methods, their behavior can be finely tuned: choosing an SMTP relay (instead of the local mail() function), disabling mailings, filtering allowed domains, adding carbon-copy recipients, and so on. This is set through the configuration file and the configuration methods (see below).


3.1textMail()

This method can be used to send simple plain-text messages.

Method signature:

textMail(string $from, string|array $to, string $title='',
         string $message='', string|array $cc='',
         string|array $bcc='', ?string $envelopeSender=null) : void

Parameters:

  • $from: Sender of the message, in the form "address@domain" or "Name <address@domain>".
  • $to: Recipient of the message, in the form "address@domain" or "Name <address@domain>".
  • $title: Title of the message.
  • $message: Textual content of the message.
  • $cc: Recipient copied to the message, or list of recipients.
  • $bcc: Recipient in hidden copy, or list of recipients.
  • $envelopeSender: Sender address sent to sendmail.

Example:

// send a plain text message
$from = 'luke@rebellion.org';
$to = 'vader@empire.com';
$title = "I can't believe it";
$text = "You are my father?";
$this->_loader['\Temma\Utils\Email']->textMail($from, $to, $title, $text);

3.2mimeMail()

This method can be used to send plain text and/or HTML e-mails, with attachments if required.

Method signature:

mimeMail(string $from, string|array $to, string $title='',
         string $html='', ?string $text=null, ?array $attachments=null,
         string|array $cc='', string|array $bcc='',
         ?string $unsubscribe=null, ?string $envelopeSender=null) : void

Parameters:

  • $from: Sender of the message, in the form "address@domain" or "Name <address@domain>".
  • $to: Recipient of the message, in the form "address@domain" or "Name <address@domain>".
  • $title: Title of the message.
  • $html: Message content in HTML format.
  • $text: Textual content of the message.
  • $attachments: List of attachments, each represented by an associative array containing the following keys:
    • filename: File name.
    • mimetype: MIME type of the file.
    • data: Binary content of the file.
  • $cc: Recipient copied to the message, or list of recipients.
  • $bcc: Recipient in hidden copy, or list of recipients.
  • $unsubscribe: Contents of SMTP List-Unsubscribe header.
  • $envelopeSender: Sender address sent to sendmail.

Example:

// sender, recipient and title of the message
$from = 'vader@empire.com';
$to = 'luke@rebellion.org';
$title = 'Hi kid';
// HTML and raw text forms of the message
$html = "<h1>Yep</h1><p>I'm your father</p>";
$text = "Yep. I'm your father";
// attached file
$attachments = [
    [
        'filename' => 'come_to_the_dark_side.pdf',
        'mimetype' => 'application/pdf',
        'data'     => file_read_contents('registration_form.pdf'),
    ],
];
// object instantiation
$email = $this->_loader['\Temma\Utils\Email'];
// send the message
$email->mimeMail($from, $to, $title, $html, $text, $attachments);

3.3templatedMail()

This method allows you to send emails in plain text and/or HTML, possibly with attachments. Text and HTML messages are generated from Smarty templates and data passed to the templates.

Method signature:

templatedMail(string $from, string|array $to, string $title='',
              ?string $htmlTplPath=null, ?string $textTplPath=null,
              ?array $templateData=null,?array $attachments=null,
              string|array $cc='', string|array $bcc='',
              ?string $unsubscribe=null, ?string $envelopeSender=null) : void

Parameters:

  • $from: Sender of the message, in the form "address@domain" or "Name <address@domain>".
  • $to: Recipient of the message, in the form "address@domain" or "Name <address@domain>".
  • $title: Title of the message.
  • $htmlTplPath: Path to HTML template.
    Can be an absolute path or a path relative to the project's templates/ directory.
  • $textTplPath: Path to template in text format.
    Can be an absolute path or a path relative to the project's templates/ directory.
  • $templateData: Associative array containing data to be transmitted to templates.
  • $attachments: List of attachments, each represented by an associative array containing the following keys:
    • filename: File name.
    • mimetype: MIME type of the file.
    • data: Binary content of the file.
  • $cc: Recipient copied to the message, or list of recipients.
  • $bcc: Recipient in hidden copy, or list of recipients.
  • $unsubscribe: Contents of SMTP List-Unsubscribe header.
  • $envelopeSender: Sender address sent to sendmail.

Example:

// sender, recipient and title of the message
$from = 'vader@empire.com';
$to = 'luke@rebellion.org';
$title = 'Hi kid';
// path to HTML and raw text templates
$htmlTpl = 'emails/message_pour_luke/html.tpl';
$textTpl = 'emails/message_pour_luke/text.tpl';
// template data
$data = [
    'name'   => 'Luky',
    'weapon' => 'Lightsaber',
];
// attached file
$attachments = [
    [
        'filename' => 'come_to_the_dark_side.pdf',
        'mimetype' => 'application/pdf',
        'data'     => file_read_contents('registration_form.pdf'),
    ],
];
// object instantiation
$email = $this->_loader['\Temma\Utils\Email'];
// send the message
$email->templatedMail($from, $to, $title, $htmlTpl, $textTpl, $data, $attachments);
HTML escaping. The HTML template is processed with auto-escaping, according to the setting of the x-smarty configuration section (autoEscape key, enabled by default). The text template, on the other hand, is never auto-escaped (HTML entities in a plain-text message body would be a mistake).

3.4Configuration file

The textMail(), mimeMail() and templatedMail() methods are affected by values that can be set in the etc/temma.php file. This makes it possible, for example, to force recipients to be copied for all messages sent.

<?php

return [
    'x-email' => [
        'disabled'       => true,
        'allowedDomains' => [ 'temma.net', 'temma.org' ],
        'cc'             => 'leia@rebellion.org',
        'bcc'            => [
            'palpatine@empire.com',
            'yoda@jedi.org',
        ],
        'envelopeSender' => 'administrator@blackstar.com',
    ]
];
  • Line 5: By adding the disabled parameter and setting it to true, you completely disable the sending of emails.
  • Line 6: List of domains to which messages can be sent.
  • Line 7: Recipient added as carbon copy. This variable can take a character string containing a recipient (of the form "address@domain.com" or "Name <address@domain.com>"), or a list of recipients.
  • Line 8: Recipients added in blind copy. This variable can take a string containing a recipient (of the form "address@domain.com" or "Name <address@domain.com>"), or a list of recipients.
  • Line 12: Definition of the address used as "envelope-sender" (also called "return path") in the SMTP envelope (MAIL FROM command). This may be necessary in the case of SMTP relays.

3.5Configuration methods

Methods can be used to modify the behavior of the textMail(), mimeMail() and templatedMail() methods. These methods overwrite any values defined in the configuration file.

$email = $this->_loader['\Temma\Utils\Email'];

// disable all mailings
$email->enable(false);
// reactivate
$email->enable(true);

// define authorized domain names
$email->setAllowedDomains(['temma.net', 'github.com']);

// add a copy recipient
$email->setCc('contact@monsupersiteweb.com');
// add multiple recipients to copy
$email->setCc(['aa@bb.com', 'yy@zz.com']);

// add one recipient as blind copy
$email->setBcc('aa@bb.com');
// add several recipients as blind copies
$email->setBcc(['aa@bb.com', 'yy@zz.com']);

// set the SMTP envelope sender ("envelope-sender", MAIL FROM command)
$email->setEnvelopeSender('administrator@blackstar.com');

// define the sending transport (see "Sending through an SMTP relay")
$email->setTransport($this->_loader->dataSources['mail']);
$email->setTransport('smtp+tls://user:pass@smtp.example.com:587');

4Sending through an SMTP relay

4.1Principle

By default, the Email helper sends messages through the PHP mail() function, that is, through the local mail server (sendmail/Postfix/Exim). This behavior is unchanged: if you configure no transport, nothing changes for existing applications.

Instead, you can configure a transport, which handles message delivery. The transport can be any data source supporting the set() method: the SMTP data source delivers the message through a relay; a File or S3 source archives it; a message queue source (SQS, Beanstalk, Redis) enqueues it; a Dummy source discards it (useful in test environments).

Only the object-oriented methods (textMail(), mimeMail(), templatedMail()) can use a transport. The static methods simpleMail() and fullMail() have no instance state: they always go through mail().

4.2Configuring the transport

There are two ways to designate the transport, in priority order:

  1. By method, at runtime (takes precedence over the configuration): the setTransport() method accepts an already instantiated data source, a DSN (any scheme), or an array of SMTP parameters.
    $email = $this->_loader['\Temma\Utils\Email'];
    
    // existing data source (declared in the "datasources" section)
    $email->setTransport($this->_loader->dataSources['mail']);
    
    // transport on the fly as a DSN
    $email->setTransport('smtp+tls://user:pass@smtp.example.com:587');
    
    // or as separate SMTP parameters
    $email->setTransport(['host' => 'smtp.example.com', 'port' => 587, 'security' => 'starttls',
                         'user' => 'user@example.com', 'password' => 'p@ss:w/rd!']);
    
  2. By configuration: the transport directive of the x-email section. It accepts three forms: the name of a data source declared in the datasources section, a DSN (any scheme), or an array of SMTP parameters. Temma then builds the data source behind the scenes.
    // name of a data source declared in the "datasources" section
    'datasources' => [
        'mail' => 'smtp+tls://user:pass@smtp.gmail.com:587',
    ],
    'x-email' => [
        'transport' => 'mail',
    ],
    
    // or a DSN directly
    'x-email' => [
        'transport' => 'smtp+tls://user:pass@smtp.gmail.com:587',
    ],
    
    // or separate SMTP parameters (handy when the password contains special characters)
    'x-email' => [
        'transport' => [
            'host'     => 'localhost',
            'port'     => 25,
            'security' => 'none',
        ],
    ],
    

A string containing "://" is treated as a DSN; any other string is treated as the name of a declared data source.

In short: runtime method > configuration. If nothing is configured, the helper uses mail().


4.3What is sent

When a transport is configured, the object-oriented methods build the message then perform a single set() call on the transport, with a structure describing the envelope and the message:

  • from: envelope sender (the envelopeSender value if defined, otherwise the From address), used for MAIL FROM;
  • recipients: deduplicated union of the to + cc + bcc recipients, used for the RCPT TO;
  • message: the full RFC 5322 message (with Date and Message-ID), without a Bcc header (blind copy recipients are in the envelope, not in the message).

This is what makes the transport portable: the envelope travels in the value passed to set(), never in the key nor in the options. A storage data source therefore archives the message without losing anything. See the SMTP data source page for details.


4.4Portability and edge cases

The transport is typed \Temma\Base\Datasource (not specifically SMTP), because the helper only calls the generic set() method. A data source that does not support set() (for example the AI/OpenAI sources) would throw a \Temma\Exceptions\Database exception; this case is marginal and not handled specifically.

Operational aspects (no code). Deliverability mostly relies on DNS configuration and the choice of relay:
  • SPF / DMARC: DNS records + an authorized relay. The only application-level lever is the control of the envelope sender (envelopeSender) and the From, already available.
  • DKIM: signing is usually handled by the relay.