# VERP: tratamento automático de bounces de email

> O que é VERP, como usar Return-Path único por mensagem para tratar bounces, como interpretar DSNs (RFC 3464) e separar auto-respostas de bounces reais.

Source: https://pidgely.com/pt-br/blog/verp-tratamento-de-bounces/ · Published: 2026-10-12 · Pidgely

VERP (Variable Envelope Return Path) é a técnica de gerar um endereço de Return-Path único para cada mensagem, como `b+7h3k9q@bounces.example.com.br`, de forma que qualquer notificação de falha enviada para esse endereço identifique automaticamente o envio e o destinatário originais. Com isso, o tratamento de bounces deixa de depender de interpretar o texto livre das mensagens de erro para descobrir quem falhou: o endereço de destino do bounce já responde. O conteúdo da DSN (RFC 3464) continua sendo usado para saber o motivo da falha.

## O problema que o VERP resolve

Existem bounces síncronos (o servidor de destino rejeita durante a conexão SMTP e o seu MTA registra) e assíncronos (o servidor aceita, tenta entregar internamente, falha e envia um email de aviso para o Return-Path). O segundo tipo é o difícil:

- O aviso pode chegar minutos ou dias depois.
- O formato varia: alguns servidores enviam DSNs bem formadas, outros um texto livre em qualquer idioma.
- O endereço que falhou pode não aparecer claramente, por exemplo quando houve encaminhamento ou alias no meio do caminho.

Se todos os seus envios usam o mesmo Return-Path (`bounces@example.com.br`), você precisa extrair o destinatário do corpo do aviso, o que falha com frequência. Com VERP, o endereço de destino já carrega a resposta.

## Como funciona

### O formato original e o formato com token

A proposta original do VERP codificava o destinatário no próprio endereço:

```text
bounces-joao=example.com.br@bounces.example.net
```

Hoje é mais comum usar um **token opaco** que referencia o envio no seu banco de dados:

```text
b+7h3k9q2m@bounces.example.com.br
```

O token opaco tem vantagens: não expõe o email do destinatário, não sofre com caracteres especiais e pode incluir uma verificação (HMAC curto) para descartar bounces forjados.

### Fluxo completo

1. A aplicação pede o envio para `joao@example.com.br`.
2. O sistema grava o envio com um ID e gera o token `7h3k9q2m`.
3. O MTA usa `MAIL FROM:<b+7h3k9q2m@bounces.example.com.br>`.
4. O servidor de destino aceita (`250`), mas depois não consegue entregar.
5. Ele envia uma DSN para `b+7h3k9q2m@bounces.example.com.br`.
6. O MX de `bounces.example.com.br` recebe, extrai o token, encontra o envio e registra o bounce.

### DNS necessário

O subdomínio de bounces precisa receber email e autorizar o envio:

```dns
bounces.example.com.br.  MX   10 inbound.bounces.example.com.br.
bounces.example.com.br.  TXT  "v=spf1 ip4:203.0.113.0/24 -all"
```

Como o SPF é verificado no domínio do Return-Path (`bounces.example.com.br`) e ele compartilha o domínio organizacional com o From (`example.com.br`), o SPF alinha no modo relaxado do DMARC. A parte variável fica antes do `@` e não afeta nada disso.

## Interpretando a DSN (RFC 3464)

Uma DSN bem formada é uma mensagem `multipart/report` com três partes: explicação legível, status por destinatário e a mensagem original (ou só os headers).

```text
From: Mail Delivery System <MAILER-DAEMON@mx.example.org>
To: b+7h3k9q2m@bounces.example.com.br
Content-Type: multipart/report; report-type=delivery-status; boundary="x"

--x
Content-Type: text/plain; charset=utf-8

Sua mensagem não pôde ser entregue.

--x
Content-Type: message/delivery-status

Reporting-MTA: dns; mx.example.org
Arrival-Date: Mon, 12 Oct 2026 10:15:02 -0300

Final-Recipient: rfc822; joao@example.org
Original-Recipient: rfc822; joao@example.com.br
Action: failed
Status: 5.1.1
Diagnostic-Code: smtp; 550 5.1.1 No such user

--x
Content-Type: text/rfc822-headers

Message-ID: <a1b2c3@example.com.br>
...
--x--
```

Os campos mais úteis:

- **`Action`**: `failed` (falha definitiva), `delayed` (ainda tentando; não é bounce), `delivered`, `relayed`, `expanded`.
- **`Status`**: enhanced status code (RFC 3463). `5.x.x` é permanente; `4.x.x` é temporário.
- **`Final-Recipient`** e **`Original-Recipient`**: o endereço que falhou e o endereço que você usou originalmente; podem ser diferentes por causa de alias ou encaminhamento.
- **`Diagnostic-Code`**: a resposta textual do servidor final.

Para classificar, use o `Status` como base e o `Diagnostic-Code` para refinar. Um `5.7.x` com texto sobre reputação ou política é bloqueio do remetente, não endereço inválido, e não deve suprimir o destinatário.

## Bounce vs auto-resposta

Nem tudo que chega no endereço de bounces é bounce. Mensagens de férias, "mudei de empresa" e confirmações de sistemas de ticket também aparecem. Suprimir esses endereços seria um erro.

Sinais de que é um **bounce real**:

- Remetente de envelope vazio: `MAIL FROM:<>`. A RFC 5321 exige o envelope vazio em notificações de falha para evitar loops.
- `Content-Type: multipart/report; report-type=delivery-status`.
- Presença de `Action: failed` e `Status: 5.x.x`.

Sinais de que é **auto-resposta**:

- Header `Auto-Submitted: auto-replied` (RFC 3834).
- Headers como `X-Autoreply`, `X-Autorespond` ou `Precedence: auto_reply`, usados por alguns sistemas.
- Assunto com padrões como "Resposta automática", "Ausente do escritório", "Out of Office".
- Ausência de estrutura de DSN.

Auto-respostas devem ser registradas (podem ser úteis para o time de suporte) e descartadas do fluxo de supressão.

## Tratando bounces sem DSN padrão

Alguns servidores enviam avisos em texto livre. Para esses:

1. Use o token VERP para saber o envio e o destinatário.
2. Procure padrões de código no corpo (`550`, `5.1.1`, `user unknown`, `mailbox unavailable`, `caixa postal inexistente`).
3. Se não houver classificação confiável, registre como "indeterminado" e só suprima depois de repetições.

## Segurança

O endereço de bounces é público e pode receber lixo ou bounces forjados (backscatter):

- Valide o token com HMAC, para ignorar tokens inventados.
- Aceite apenas tokens de envios recentes (por exemplo, das últimas semanas).
- Não responda a mensagens recebidas no domínio de bounces.
- Limite o tamanho da mensagem aceita.

## Erros comuns

- Usar um único Return-Path para tudo e depender do texto da mensagem de erro.
- Colocar o Return-Path no domínio do fornecedor, quebrando o alinhamento do DMARC.
- Tratar `Action: delayed` como bounce.
- Suprimir endereços por causa de auto-respostas.
- Esquecer o MX do subdomínio de bounces e perder todos os avisos assíncronos.

## Checklist

- [ ] Return-Path com token único por mensagem em subdomínio próprio.
- [ ] MX e SPF configurados no subdomínio de bounces.
- [ ] Parser de DSN (RFC 3464) com fallback para texto livre.
- [ ] Separação entre bounce e auto-resposta (RFC 3834).
- [ ] Classificação por enhanced status code, sem suprimir bloqueios de política.
- [ ] Token validado por HMAC e com prazo.

## Na Pidgely

A Pidgely usa VERP com token assinado em um subdomínio de return-path por domínio verificado, interpreta DSNs e respostas síncronas, separa auto-respostas, alimenta a lista de supressão e entrega cada bounce como evento de webhook assinado para a sua aplicação.

## Perguntas frequentes

### O que é VERP?

VERP (Variable Envelope Return Path) é a técnica de usar um endereço de Return-Path diferente para cada mensagem ou destinatário. Quando o bounce chega, o próprio endereço diz a qual envio ele se refere, sem precisar interpretar o conteúdo.

### VERP quebra o SPF ou o DMARC?

Não, desde que o domínio do Return-Path seja um subdomínio seu com SPF configurado. A parte variável fica antes do @, então o domínio verificado pelo SPF continua o mesmo e alinha com o From no modo relaxado.

### Como diferenciar uma auto-resposta de férias de um bounce?

Bounces de verdade chegam com remetente vazio no envelope (MAIL FROM:<>) e geralmente em multipart/report com report-type=delivery-status. Auto-respostas costumam ter o header Auto-Submitted: auto-replied, definido na RFC 3834, e não devem gerar supressão.

### Preciso de VERP se meu MTA já registra respostas SMTP?

Sim. Os logs cobrem rejeições durante a conexão, mas muitos bounces são assíncronos: o servidor aceita com 250 e só depois avisa da falha por email. Sem VERP, associar esse aviso ao envio original é frágil.

