Helper Email


1Apresentação

Helper para envio de e-mails, com a opção de enviar mensagens simples em texto puro, ou mensagens mais complexas (formato HTML e texto, anexos).

O objeto \Temma\Utils\Email oferece duas famílias de métodos.

Os métodos estáticos (simpleMail(), fullMail()) permitem enviar um e-mail rapidamente. Eles dependem da função nativa mail() do PHP: portanto, exigem um servidor SMTP local (um MTA como sendmail, Postfix ou Exim) instalado e configurado na máquina.

Os métodos orientados a objetos (textMail(), mimeMail(), templatedMail()) são usados por meio do componente de injeção de dependências e aproveitam os parâmetros configurados no arquivo etc/temma.php: escolha de um relay SMTP, desativação dos envios, filtragem dos domínios permitidos, adição de destinatários em cópia, entre outros. Se o transporte não estiver configurado, eles também usam a função mail().

É fortemente recomendado usar os métodos orientados a objetos (em vez dos métodos estáticos), pois isso permite configurar os envios. Por exemplo, você pode desativar os envios ao implantar seu site em um servidor de teste; ou restringir os envios a determinados domínios.

2Métodos estáticos

Esses métodos enviam mensagens por meio da função nativa mail() do PHP: portanto, exigem um servidor SMTP local (sendmail, Postfix, Exim…) instalado e configurado na máquina. Por não terem estado de instância, eles não levam em conta nem a configuração x-email nem um relay; para isso, use os métodos orientados a objetos.

2.1simpleMail()

Este método estático facilita o envio de um e-mail com conteúdo em texto puro.

Assinatura do método:

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

Parâmetros:

  • $from: Remetente da mensagem, no formato "endereco@dominio" ou "Nome <endereco@dominio>".
  • $to: Destinatário da mensagem, no formato "endereco@dominio" ou "Nome <endereco@dominio>".
  • $title: Título da mensagem.
  • $message: Conteúdo textual da mensagem.
  • $cc: Destinatário em cópia da mensagem, ou lista de destinatários.
  • $bcc: Destinatário em cópia oculta, ou lista de destinatários.
  • $envelopeSender: Endereço do remetente enviado ao sendmail.

Exemplo:

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

// envia uma mensagem em texto puro
TµEmail::simpleMail('luke@rebellion.org', 'vader@empire.com',
                    "Não acredito nisso", "Você é meu pai?");

2.2fullMail()

Este método estático pode ser usado para enviar e-mails em texto puro e/ou HTML, com anexos se necessário.

Assinatura do método:

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

Parâmetros:

  • $from: Remetente da mensagem, no formato "endereco@dominio" ou "Nome <endereco@dominio>".
  • $to: Destinatário da mensagem, no formato "endereco@dominio" ou "Nome <endereco@dominio>".
  • $title: Título da mensagem.
  • $html: Conteúdo da mensagem em formato HTML.
  • $text: Conteúdo textual da mensagem.
  • $attachments: Lista de anexos, cada um representado por um array associativo contendo as seguintes chaves:
    • filename: Nome do arquivo.
    • mimetype: Tipo MIME do arquivo.
    • data: Conteúdo binário do arquivo.
  • $cc: Destinatário em cópia da mensagem, ou lista de destinatários.
  • $bcc: Destinatário em cópia oculta, ou lista de destinatários.
  • $unsubscribe: Conteúdo do cabeçalho SMTP List-Unsubscribe.
  • $envelopeSender: Endereço do remetente enviado ao sendmail.

Exemplo:

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

TµEmail::fullMail('vader@empire.com', "luke@rebellion.org",
                  "E aí, garoto", "<h1>Pois é</h1><p>Eu sou seu pai</p>");

3Métodos orientados a objetos

Esses métodos exigem que o objeto seja instanciado por meio do componente de injeção de dependências.

Ao contrário dos métodos estáticos, seu comportamento pode ser ajustado com precisão: escolha de um relay SMTP (em vez da função local mail()), desativação dos envios, filtragem dos domínios permitidos, adição de destinatários em cópia, entre outros. Isso é definido por meio do arquivo de configuração e dos métodos de configuração (veja abaixo).


3.1textMail()

Este método pode ser usado para enviar mensagens simples em texto puro.

Assinatura do método:

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

Parâmetros:

  • $from: Remetente da mensagem, no formato "endereco@dominio" ou "Nome <endereco@dominio>".
  • $to: Destinatário da mensagem, no formato "endereco@dominio" ou "Nome <endereco@dominio>".
  • $title: Título da mensagem.
  • $message: Conteúdo textual da mensagem.
  • $cc: Destinatário em cópia da mensagem, ou lista de destinatários.
  • $bcc: Destinatário em cópia oculta, ou lista de destinatários.
  • $envelopeSender: Endereço do remetente enviado ao sendmail.

Exemplo:

// envia uma mensagem em texto puro
$from = 'luke@rebellion.org';
$to = 'vader@empire.com';
$title = "Não acredito nisso";
$text = "Você é meu pai?";
$this->_loader['\Temma\Utils\Email']->textMail($from, $to, $title, $text);

3.2mimeMail()

Este método pode ser usado para enviar e-mails em texto puro e/ou HTML, com anexos se necessário.

Assinatura do método:

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

Parâmetros:

  • $from: Remetente da mensagem, no formato "endereco@dominio" ou "Nome <endereco@dominio>".
  • $to: Destinatário da mensagem, no formato "endereco@dominio" ou "Nome <endereco@dominio>".
  • $title: Título da mensagem.
  • $html: Conteúdo da mensagem em formato HTML.
  • $text: Conteúdo textual da mensagem.
  • $attachments: Lista de anexos, cada um representado por um array associativo contendo as seguintes chaves:
    • filename: Nome do arquivo.
    • mimetype: Tipo MIME do arquivo.
    • data: Conteúdo binário do arquivo.
  • $cc: Destinatário em cópia da mensagem, ou lista de destinatários.
  • $bcc: Destinatário em cópia oculta, ou lista de destinatários.
  • $unsubscribe: Conteúdo do cabeçalho SMTP List-Unsubscribe.
  • $envelopeSender: Endereço do remetente enviado ao sendmail.

Exemplo:

// remetente, destinatário e título da mensagem
$from = 'vader@empire.com';
$to = 'luke@rebellion.org';
$title = 'E aí, garoto';
// versões HTML e texto puro da mensagem
$html = "<h1>Pois é</h1><p>Eu sou seu pai</p>";
$text = "Pois é. Eu sou seu pai";
// arquivo anexado
$attachments = [
    [
        'filename' => 'come_to_the_dark_side.pdf',
        'mimetype' => 'application/pdf',
        'data'     => file_read_contents('registration_form.pdf'),
    ],
];
// instanciação do objeto
$email = $this->_loader['\Temma\Utils\Email'];
// envia a mensagem
$email->mimeMail($from, $to, $title, $html, $text, $attachments);

3.3templatedMail()

Este método permite enviar e-mails em texto puro e/ou HTML, possivelmente com anexos. As mensagens em texto e HTML são geradas a partir de templates Smarty e dos dados passados aos templates.

Assinatura do método:

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

Parâmetros:

  • $from: Remetente da mensagem, no formato "endereco@dominio" ou "Nome <endereco@dominio>".
  • $to: Destinatário da mensagem, no formato "endereco@dominio" ou "Nome <endereco@dominio>".
  • $title: Título da mensagem.
  • $htmlTplPath: Caminho para o template HTML.
    Pode ser um caminho absoluto ou um caminho relativo ao diretório templates/ do projeto.
  • $textTplPath: Caminho para o template em formato texto.
    Pode ser um caminho absoluto ou um caminho relativo ao diretório templates/ do projeto.
  • $templateData: Array associativo contendo os dados a serem transmitidos aos templates.
  • $attachments: Lista de anexos, cada um representado por um array associativo contendo as seguintes chaves:
    • filename: Nome do arquivo.
    • mimetype: Tipo MIME do arquivo.
    • data: Conteúdo binário do arquivo.
  • $cc: Destinatário em cópia da mensagem, ou lista de destinatários.
  • $bcc: Destinatário em cópia oculta, ou lista de destinatários.
  • $unsubscribe: Conteúdo do cabeçalho SMTP List-Unsubscribe.
  • $envelopeSender: Endereço do remetente enviado ao sendmail.

Exemplo:

// remetente, destinatário e título da mensagem
$from = 'vader@empire.com';
$to = 'luke@rebellion.org';
$title = 'E aí, garoto';
// caminho para os templates HTML e texto puro
$htmlTpl = 'emails/message_pour_luke/html.tpl';
$textTpl = 'emails/message_pour_luke/text.tpl';
// dados do template
$data = [
    'name'   => 'Luky',
    'weapon' => 'Lightsaber',
];
// arquivo anexado
$attachments = [
    [
        'filename' => 'come_to_the_dark_side.pdf',
        'mimetype' => 'application/pdf',
        'data'     => file_read_contents('registration_form.pdf'),
    ],
];
// instanciação do objeto
$email = $this->_loader['\Temma\Utils\Email'];
// envia a mensagem
$email->templatedMail($from, $to, $title, $htmlTpl, $textTpl, $data, $attachments);
Escape de HTML. O template HTML é processado com auto-escape, de acordo com a configuração da seção x-smarty (chave autoEscape, habilitada por padrão). Já o template de texto, por sua vez, nunca passa por auto-escape (entidades HTML no corpo de uma mensagem em texto puro seriam um erro).

3.4Arquivo de configuração

Os métodos textMail(), mimeMail() e templatedMail() são afetados por valores que podem ser definidos no arquivo etc/temma.php. Isso permite, por exemplo, forçar a cópia de destinatários em todas as mensagens enviadas.

<?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',
    ]
];
  • Linha 5: Ao adicionar o parâmetro disabled e defini-lo como true, você desativa completamente o envio de e-mails.
  • Linha 6: Lista de domínios para os quais as mensagens podem ser enviadas.
  • Linha 7: Destinatário adicionado em cópia. Esta variável pode receber uma string de caracteres contendo um destinatário (no formato "endereco@dominio.com" ou "Nome <endereco@dominio.com>"), ou uma lista de destinatários.
  • Linha 8: Destinatários adicionados em cópia oculta. Esta variável pode receber uma string contendo um destinatário (no formato "endereco@dominio.com" ou "Nome <endereco@dominio.com>"), ou uma lista de destinatários.
  • Linha 12: Definição do endereço usado como "envelope-sender" (também chamado de "return path") no envelope SMTP (comando MAIL FROM). Isso pode ser necessário no caso de relays SMTP.

3.5Métodos de configuração

É possível usar métodos para modificar o comportamento dos métodos textMail(), mimeMail() e templatedMail(). Esses métodos sobrescrevem quaisquer valores definidos no arquivo de configuração.

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

// desativa todos os envios
$email->enable(false);
// reativa
$email->enable(true);

// define os nomes de domínio autorizados
$email->setAllowedDomains(['temma.net', 'github.com']);

// adiciona um destinatário em cópia
$email->setCc('contact@monsupersiteweb.com');
// adiciona múltiplos destinatários em cópia
$email->setCc(['aa@bb.com', 'yy@zz.com']);

// adiciona um destinatário em cópia oculta
$email->setBcc('aa@bb.com');
// adiciona vários destinatários em cópia oculta
$email->setBcc(['aa@bb.com', 'yy@zz.com']);

// define o remetente do envelope SMTP ("envelope-sender", comando MAIL FROM)
$email->setEnvelopeSender('administrator@blackstar.com');

// define o transporte de envio (veja "Envio por meio de um relay SMTP")
$email->setTransport($this->_loader->dataSources['mail']);
$email->setTransport('smtp+tls://user:pass@smtp.example.com:587');

4Envio por meio de um relay SMTP

4.1Princípio

Por padrão, o helper Email envia mensagens por meio da função mail() do PHP, ou seja, através do servidor de e-mail local (sendmail/Postfix/Exim). Esse comportamento permanece inalterado: se você não configurar nenhum transporte, nada muda para as aplicações existentes.

Como alternativa, você pode configurar um transporte, responsável pela entrega da mensagem. O transporte pode ser qualquer fonte de dados que suporte o método set(): a fonte de dados SMTP entrega a mensagem por meio de um relay; uma fonte File ou S3 a arquiva; uma fonte de fila de mensagens (SQS, Beanstalk, Redis) a enfileira; uma fonte Dummy a descarta (útil em ambientes de teste).

Somente os métodos orientados a objetos (textMail(), mimeMail(), templatedMail()) podem usar um transporte. Os métodos estáticos simpleMail() e fullMail() não têm estado de instância: eles sempre passam pela função mail().

4.2Configurando o transporte

Existem duas maneiras de designar o transporte, em ordem de prioridade:

  1. Por método, em tempo de execução (tem precedência sobre a configuração): o método setTransport() aceita uma fonte de dados já instanciada, uma DSN (qualquer esquema), ou um array de parâmetros SMTP.
    $email = $this->_loader['\Temma\Utils\Email'];
    
    // fonte de dados existente (declarada na seção "datasources")
    $email->setTransport($this->_loader->dataSources['mail']);
    
    // transporte definido diretamente como uma DSN
    $email->setTransport('smtp+tls://user:pass@smtp.example.com:587');
    
    // ou como parâmetros SMTP separados
    $email->setTransport(['host' => 'smtp.example.com', 'port' => 587, 'security' => 'starttls',
                         'user' => 'user@example.com', 'password' => 'p@ss:w/rd!']);
    
  2. Por configuração: a diretiva transport da seção x-email. Ela aceita três formas: o nome de uma fonte de dados declarada na seção datasources, uma DSN (qualquer esquema), ou um array de parâmetros SMTP. O Temma então constrói a fonte de dados nos bastidores.
    // nome de uma fonte de dados declarada na seção "datasources"
    'datasources' => [
        'mail' => 'smtp+tls://user:pass@smtp.gmail.com:587',
    ],
    'x-email' => [
        'transport' => 'mail',
    ],
    
    // ou uma DSN diretamente
    'x-email' => [
        'transport' => 'smtp+tls://user:pass@smtp.gmail.com:587',
    ],
    
    // ou parâmetros SMTP separados (útil quando a senha contém caracteres especiais)
    'x-email' => [
        'transport' => [
            'host'     => 'localhost',
            'port'     => 25,
            'security' => 'none',
        ],
    ],
    

Uma string contendo "://" é tratada como uma DSN; qualquer outra string é tratada como o nome de uma fonte de dados declarada.

Em resumo: método em tempo de execução > configuração. Se nada estiver configurado, o helper usa mail().


4.3O que é enviado

Quando um transporte é configurado, os métodos orientados a objetos constroem a mensagem e, em seguida, realizam uma única chamada set() no transporte, com uma estrutura que descreve o envelope e a mensagem:

  • from: remetente do envelope (o valor de envelopeSender se definido, caso contrário o endereço From), usado no MAIL FROM;
  • recipients: união sem duplicatas dos destinatários to + cc + bcc, usada no RCPT TO;
  • message: a mensagem completa no formato RFC 5322 (com Date e Message-ID), sem cabeçalho Bcc (os destinatários em cópia oculta estão no envelope, não na mensagem).

É isso que torna o transporte portátil: o envelope viaja no valor passado a set(), nunca na chave nem nas opções. Uma fonte de dados de armazenamento, portanto, arquiva a mensagem sem perder nada. Veja a página da fonte de dados SMTP para mais detalhes.


4.4Portabilidade e casos extremos

O transporte é tipado como \Temma\Base\Datasource (não especificamente SMTP), pois o helper chama apenas o método genérico set(). Uma fonte de dados que não suporte set() (por exemplo, as fontes AI/OpenAI) geraria uma exceção \Temma\Exceptions\Database; esse caso é marginal e não é tratado especificamente.

Aspectos operacionais (sem código). A capacidade de entrega depende principalmente da configuração de DNS e da escolha do relay:
  • SPF / DMARC: registros DNS + um relay autorizado. A única alavanca no nível da aplicação é o controle do remetente do envelope (envelopeSender) e do From, já disponível.
  • DKIM: a assinatura geralmente é feita pelo relay.