Fonte de dados: SMTP


1Apresentação

Esta fonte de dados é um cliente SMTP minimalista, que envia e-mails conectando-se a um configurável relay SMTP: um servidor externo (Gmail, Mailgun, Mailjet, Brevo…) ou um local (Postfix/Exim em smtp://localhost).

Ela não depende de nenhuma biblioteca externa (usa sockets PHP diretamente) e se conecta a um único relay. A entrega direta ao servidor MX do destinatário não é suportada: um relay é sempre necessário.

Assim como as fontes de dados Slack ou Discord, esta é uma fonte de dados somente para escrita: os métodos de leitura (get(), read(), find()…) são inertes ou lançam uma exceção.

Se você configurou corretamente os parâmetros de conexão, o Temma cria automaticamente um objeto do tipo \Temma\Datasources\Smtp. Por convenção, vamos supor que você nomeou essa conexão smtp no arquivo etc/temma.php (veja a documentação de configuração).

Nos controladores, a conexão fica então disponível da seguinte forma:

$smtp = $this->smtp;

Nos demais objetos gerenciados pelo componente de injeção de dependências, a conexão é acessível da seguinte forma:

$smtp = $loader->dataSources->smtp;
$smtp = $loader->dataSources['smtp'];
Na maioria dos casos, você não usará esta fonte de dados diretamente: você a configurará como o transporte do helper Email, que monta as mensagens e delega a entrega ao relay. Veja a seção Envio por meio de um relay SMTP.

2Configuração

2.1DSN

No arquivo etc/temma.php (veja a documentação de configuração), você declara o DSN (Data Source Name) usado para se conectar ao relay SMTP. Três esquemas estão disponíveis, dependendo do modo de criptografia da conexão:

  • smtp://[user:password@]server[:port]
    Conexão em texto puro. Porta padrão: 25.
  • smtp+tls://[user:password@]server[:port]
    Conexão criptografada via STARTTLS (a criptografia é negociada após a conexão). Porta padrão: 587.
  • smtps://[user:password@]server[:port]
    Conexão criptografada desde o início (TLS implícito). Porta padrão: 465.

A autenticação é opcional: ela só é ativada se o DSN contiver um par user:password (mecanismos PLAIN ou LOGIN, de preferência sobre uma conexão criptografada). Um relay local como smtp://localhost:25 se conecta, portanto, sem autenticação.

Exemplos:

// relay do Gmail com STARTTLS e autenticação
'smtp+tls://user:password@smtp.gmail.com:587'

// relay local sem autenticação
'smtp://localhost:25'
Se o nome de usuário ou a senha contiver caracteres especiais (@, :, /…), eles devem ser codificados para URL no DSN, ou você pode usar a construção a partir de parâmetros separados.

A fábrica de fontes de dados reconhece os prefixos smtp://, smtp+tls:// e smtps://. A forma genérica também pode ser usada: [\Temma\Datasources\Smtp]smtp://….


2.2Parâmetros opcionais

O DSN aceita parâmetros de consulta opcionais:

  • helo: nome anunciado no comando EHLO/HELO.
  • timeout: tempo limite de rede, em segundos.
  • verify: verificação do certificado TLS (1 para ativar, 0 para desativar; ativado por padrão).
smtp+tls://user:pass@smtp.example.com:587?helo=mysite.com&timeout=10&verify=1

2.3Construção a partir de parâmetros

Uma senha (ou nome de usuário) contendo caracteres especiais é incômoda de codificar em um DSN. Você pode então descrever a conexão usando parâmetros separados em vez de um DSN. Os parâmetros aceitos são: host, port, user, password, security (none, starttls ou tls), helo, timeout e verify.

'x-email' => [
    'transport' => [
        'host'     => 'smtp.example.com',
        'port'     => 587,
        'user'     => 'user@example.com',
        'password' => 'p@ss:w/rd!',
        'security' => 'starttls',
    ],
],

Essa forma é equivalente ao DSN correspondente. Ela é usada, em particular, pelo helper Email através da diretiva transport em forma de array.


3Envelope e mensagem

O envio de um e-mail SMTP se baseia em duas noções distintas:

  • o envelope: o remetente (MAIL FROM) e a lista de destinatários (RCPT TO) realmente usados pelo protocolo SMTP;
  • a mensagem: o fluxo completo RFC 5322 (From, To, Cc, Subject, Date, Message-ID, cabeçalhos MIME… e o corpo).

O envelope e a mensagem são independentes. Por exemplo, os destinatários em cópia oculta aparecem no envelope (para que a entrega seja feita) mas não nos cabeçalhos da mensagem (sem cabeçalho Bcc).

A fonte de dados cuida da transparência SMTP (normalização das quebras de linha para CRLF e "dot-stuffing" das linhas do corpo que começam com um ponto). Você fornece uma mensagem RFC 5322 normal; a conformidade no nível do protocolo é automática.


4Envio

4.1set()

O método set() é o caminho normal de envio (é o que é usado pelo helper Email). Ele espera um valor em array estruturado descrevendo o envelope e a mensagem:

$smtp->set($id, [
    'from'       => 'sender@example.com',
    'recipients' => ['dest1@example.com', 'dest2@example.com'],
    'message'    => $rawRfc5322Message,
]);
  • from: remetente do envelope, usado para MAIL FROM.
  • recipients: lista de destinatários, um RCPT TO por entrada.
  • message: fluxo RFC 5322 completo, enviado em DATA.

O primeiro parâmetro ($id) é um simples identificador (Message-ID ou identificador da aplicação), usado para o log.

Essa estrutura "portátil" é o que possibilita usar qualquer fonte de dados como transporte: uma fonte SMTP entrega a mensagem, uma fonte File ou S3 a arquiva, uma fonte de fila de mensagens a coloca na fila, e assim por diante. O envelope viaja no valor, nunca nas opções nem na chave.


4.2write()

O método write() oferece acesso bruto: o valor é diretamente o fluxo RFC 5322, e o envelope é passado no terceiro parâmetro ($options).

$smtp->write($id, $rawRfc5322Message, [
    'from'       => 'sender@example.com',
    'recipients' => ['dest1@example.com', 'dest2@example.com'],
]);

O envio é imediato em ambos os casos.


5Uso do helper Email

Na prática, esta fonte de dados serve principalmente como transporte para o helper Email. Você então não chama nem set() nem write() diretamente: o helper monta a mensagem e o envelope, e então delega o envio. Consulte a seção Envio por meio de um relay SMTP do helper Email.