Adgora
Guias 5 min de leitura 982 palavras

Envio confiável de e-mails SMTP com Node.js

Aprenda a enviar notificações em segundo plano com Node.js, usando uma fila persistente, chaves idempotentes e novas tentativas controladas.

Adgora
Nesta página0%

    A aprovação de uma campanha, uma alteração de saldo ou um alerta de segurança da conta não deve deixar um pedido Node.js à espera de um servidor de e-mail. Se o relay estiver lento, a ação apresentada ao utilizador pode expirar; se a aplicação repetir o pedido, pode enviar a mesma mensagem duas vezes. Uma configuração de produção mais segura consiste em registar a notificação juntamente com o evento de negócio e, depois, deixar que um worker em segundo plano a envie por SMTP. Este guia mostra como enviar e-mails em segundo plano com Node.js sem bloquear os pedidos da aplicação.

    Retire o envio de e-mails do fluxo dos pedidos

    Numa rede de anúncios de criptomoedas, imagine uma campanha que passa de pendente para aprovada. A aplicação deve confirmar rapidamente essa alteração de estado e enviar mensagens transacionais e de marketing sem depender de uma ligação SMTP ser concluída antes de responder ao anunciante.

    Guarde um trabalho de envio de e-mail numa tabela da base de dados ou numa fila persistente, como parte da mesma transação que confirma a alteração de estado. Um worker lê os trabalhos pendentes e envia as mensagens através do relay. Assim, a disponibilidade da aplicação fica separada da entrega de e-mails: uma interrupção temporária do relay pode atrasar a notificação sem anular uma aprovação nem bloquear uma ação no painel.

    Se estiver a integrar um relay SMTP em Node.js num serviço existente, encare a separação do worker como a principal decisão de arquitetura, não a biblioteca de e-mail. A plataforma de e-mail e mensagens pode fornecer a ligação SMTP para mensagens transacionais, mas continua a caber à aplicação decidir quando criar uma mensagem, como gerir novas tentativas e o que fazer quando não é possível confirmar a entrega.

    Crie um único trabalho de notificação para cada evento de negócio

    Crie o trabalho quando o evento subjacente for confirmado, em vez de o gerar sempre que uma página é carregada ou que um utilizador repete um pedido à API. Atribua ao trabalho uma chave de evento estável, como o identificador da campanha, a transição de estado e a versão. Imponha a unicidade dessa chave para que pedidos duplicados não criem vários e-mails de aprovação pendentes; esta é uma parte importante de como evitar e-mails duplicados numa fila de notificações.

    Um registo de trabalho útil inclui o destinatário, um identificador de modelo, os dados mínimos necessários para compor a mensagem, o número de tentativas, a hora da próxima tentativa e o estado. Evite guardar credenciais SMTP ou informações desnecessárias da conta. Se o endereço do destinatário puder mudar antes do envio, decida se o trabalho deve usar o endereço registado no momento do evento ou o endereço atualmente verificado da conta; deixe essa política explícita.

    Associe o e-mail gerado a uma alteração de estado real. Um worker não deve deduzir que houve uma aprovação com base numa informação desatualizada na fila. Antes de enviar um alerta sensível, pode verificar a versão atual do evento ou carregar o registo relevante. Assim, evita informar um cliente de que uma campanha foi aprovada se esta tiver sido colocada em pausa logo a seguir.

    Configure o relay Node.js no worker

    Utilize um cliente SMTP mantido, como o Nodemailer, e leia os dados da ligação a partir do ambiente do worker, em vez de os guardar no código-fonte. Para configurar SMTP com Nodemailer no Node.js, comece por definir as variáveis de ambiente necessárias e ajuste a porta e as definições de TLS de acordo com as credenciais fornecidas para a sua conta. O exemplo seguinte utiliza a porta de envio normalmente usada.

    const nodemailer = require("nodemailer");
    
    const port = Number(process.env.SMTP_PORT || 587);
    
    const transporter = nodemailer.createTransport({
      host: process.env.SMTP_HOST,
      port,
      secure: port === 465,
      requireTLS: port !== 465,
      auth: {
        user: process.env.SMTP_USER,
        pass: process.env.SMTP_PASS
      }
    });
    
    async function sendCampaignNotice(message) {
      return transporter.sendMail({
        from: process.env.MAIL_FROM,
        to: message.to,
        subject: message.subject,
        text: message.text,
        html: message.html
      });
    }

    Defina como remetente um endereço aprovado para a sua configuração de envio e utilize uma credencial própria para o worker, em vez de reutilizar o acesso de administrador. Não registe nos logs a mensagem completa, a palavra-passe nem a resposta de autenticação. Uma verificação no arranque pode detetar definições inválidas, mas não garante que um destinatário específico aceite uma mensagem enviada mais tarde.

    Repita as tentativas perante falhas temporárias sem sobrecarregar o sistema com e-mails

    Classifique as falhas em vez de repetir todas ao mesmo ritmo. Uma falha temporária de ligação ou uma resposta do servidor a indicar que o serviço está ocupado pode justificar novas tentativas com intervalos crescentes. Credenciais inválidas, destinatários malformados e outros erros persistentes de configuração ou de endereço exigem investigação, não tentativas rápidas e repetidas. Defina um número máximo de tentativas e encaminhe os trabalhos que o excedam para um estado que possa ser analisado por um operador.

    Utilize um mecanismo de lease do worker, ou equivalente, para impedir que dois processos Node.js enviem o mesmo trabalho pendente ao mesmo tempo. Quando um worker assume um trabalho, registe a expiração do lease; se o processo falhar, outro worker poderá voltar a assumir o trabalho após essa expiração. Defina a duração do lease para ser superior ao tempo limite normal de envio e prolongue-a se a composição ou a entrega da mensagem puder demorar mais.

    O SMTP não pode garantir que a sua aplicação envie uma mensagem exatamente uma vez. O relay pode aceitar uma mensagem e a ligação falhar antes de o worker receber a confirmação. Nesse caso, uma nova tentativa pode gerar uma duplicação; se o trabalho for marcado como enviado antes da aceitação, a mensagem pode perder-se. Utilize chaves de evento estáveis para evitar a criação de trabalhos duplicados, limite as novas tentativas e aceite que nem sempre é possível resolver automaticamente este caso específico de resultado incerto.

    Implemente a alteração de forma faseada

    Antes de encaminhar o tráfego de produção, envie trabalhos de teste a partir de um ambiente não produtivo e confirme que o worker consegue autenticar-se, compor o conteúdo esperado e registar os estados de sucesso e de falha. Depois, ative o worker para um tipo de notificação de baixo risco. Compare o número de eventos de negócio, trabalhos na fila e envios concluídos; uma fila cujo atraso aumenta pode revelar um problema no worker ou na configuração antes de avançar para os alertas críticos.

    • Mantenha a aplicação Web e o worker a utilizar o mesmo esquema de mensagens durante a implementação.
    • Torne idempotente a criação de trabalhos antes de executar várias instâncias do worker.
    • Monitorize a antiguidade dos trabalhos na fila, o número de novas tentativas, as falhas permanentes e o estado do worker.
    • Mantenha uma opção de reenvio manual para falhas analisadas, em vez de reenviar indiscriminadamente todos os trabalhos com falhas.

    Quando o worker estiver estável, remova os envios SMTP diretos dos handlers dos pedidos para que estas mensagens tenham um único fluxo controlado. Se utilizar a plataforma de e-mail e mensagens como relay, esta trata do envio por SMTP; a fila, as regras dos eventos, a política de novas tentativas e a análise operacional continuam a ser da sua responsabilidade. Esta separação é útil quando os eventos da conta têm de ser registados rapidamente, mesmo durante breves interrupções do serviço de e-mail, mas não dispensa a monitorização nem uma política clara para notificações atrasadas.

    Compartilhe este artigo

    Achou útil? Envie para alguém que compra ou vende tráfego.

    Próximo passo

    Pronto para colocar isso em prática?

    Lance uma campanha ou monetize seu tráfego no Adgora — pagamentos em cripto, estatísticas em tempo real, sem compromisso.

    O que esta página responde