Boas Práticas de AMPscript
Escrever AMPscript que funciona é uma coisa. Escrever AMPscript que outra pessoa consegue entender seis meses depois - inclusive você mesmo - é outra história.
Este guia reúne convenções de nomenclatura, organização de código e técnicas defensivas que fazem diferença no dia a dia. Nada aqui é regra absoluta da linguagem: AMPscript é flexível e tolerante. Mas flexibilidade sem disciplina vira bagunça rápido.
💡 Dois princípios que valem mais que qualquer regra:
- Seja consistente no seu projeto.
- Priorize legibilidade.
Nomenclatura
Nomes descritivos
O código que você escreve hoje vai ser lido no futuro - por um colega, por um consultor externo, ou por você mesmo depois de dois meses sem ver aquele template. Use nomes que expliquem o propósito da variável, não só o valor.
/* ✅ Nome que diz o que é */
SET @dataDeVencimento = DateAdd(Now(), 30, 'D')
SET @isPrimeiraCompra = IIF(Empty(@totalPedidos), true, false)
/* ❌ Nome que não diz nada */
SET @data = DateAdd(Now(), 30, 'D')
SET @flag = IIF(Empty(@x), true, false)
Algumas convenções que ajudam:
- Variáveis booleanas começam com
is,has,podeoutem-isAtivo,temSaldo,podeReceberEmail - Variáveis de data terminam com
DataouDate-dataEnvio,dataVencimento - Variáveis que guardam resultados de Lookup começam com o nome da DE -
clienteNome,pedidoStatus
Convenção de caixa
AMPscript não liga para maiúsculas ou minúsculas - lookup e LOOKUP e Lookup funcionam igual. O problema é quando o mesmo projeto usa os três ao mesmo tempo. Escolha uma convenção e siga ela.
A convenção mais adotada pela comunidade - e a que recomendamos aqui - é:
| Elemento | Estilo | Exemplo |
|---|---|---|
| Variáveis | camelCase | @nomeCompleto, @totalPedidos |
| Funções | PascalCase | Lookup(), FormatDate(), Concat() |
Palavras-chave (SET, IF, FOR) | MAIÚSCULAS | SET, IF THEN, FOR DO NEXT |
%%[
/* ✅ Convenção consistente */
SET @nomeCliente = Lookup('Clientes_DE', 'NomeCompleto', 'Email', emailaddr)
SET @isPremium = Lookup('Clientes_DE', 'PlanoAtivo', 'Email', emailaddr)
IF @isPremium == 'Premium' THEN
SET @desconto = '15%'
ELSE
SET @desconto = '5%'
ENDIF
]%%
Aspas: simples ou duplas?
AMPscript aceita as duas. O importante é não misturar no mesmo projeto.
Preferimos aspas simples porque:
- É mais fácil de digitar (sem Shift)
- Evita conflito com atributos HTML que usam aspas duplas
/* ✅ Aspas simples consistentes */
SET @produto = Lookup('Catalogo_DE', 'NomeProduto', 'SKU', @sku)
/* ❌ Mistura de aspas */
SET @produto = Lookup("Catalogo_DE", 'NomeProduto', "SKU", @sku)
Organização do código
Código no topo
Coloque todo o bloco %%[ ]%% principal no início do template - antes de qualquer HTML. Isso facilita manutenção, torna o código fácil de localizar e evita problemas com a versão texto do e-mail.
%%[
/* Todo o AMPscript aqui, no topo */
SET @nomeCliente = Lookup('Clientes_DE', 'Nome', 'Email', emailaddr)
SET @saldoPontos = Lookup('Fidelidade_DE', 'Saldo', 'Email', emailaddr)
SET @isPremium = IIF(@saldoPontos > 5000, true, false)
]%%
<!DOCTYPE html>
<html>
<!-- HTML do e-mail abaixo -->
Variáveis no bloco, v() no corpo
Calcule tudo no bloco do topo e use %%=v(@variavel)=%% no corpo do HTML. Evite aninhar funções diretamente no HTML - fica ilegível e difícil de depurar.
/* ✅ Cálculo no bloco, exibição limpa no HTML */
%%[
SET @preco = Lookup('Produtos_DE', 'Preco', 'SKU', @sku)
SET @precoFormatado = FormatNumber(@preco, '###.##0,00', 'pt-BR')
SET @nomeProduto = Lookup('Produtos_DE', 'Nome', 'SKU', @sku)
]%%
<p>%%=v(@nomeProduto)=%% - R$ %%=v(@precoFormatado)=%%</p>
/* ❌ Funções aninhadas direto no HTML */
<p>%%=Lookup('Produtos_DE', 'Nome', 'SKU', @sku)=%% - R$ %%=FormatNumber(Lookup('Produtos_DE', 'Preco', 'SKU', @sku), '###.##0,00', 'pt-BR')=%%</p>
Indentação
Sem chaves {} para delimitar blocos, a indentação é o único recurso visual para entender estrutura. Use 4 espaços (não tab) dentro de IF e FOR.
%%[
SET @rowset = LookupRows('Pedidos_DE', 'Email', emailaddr)
SET @total = RowCount(@rowset)
IF @total > 0 THEN
FOR @i = 1 TO @total DO
SET @row = Row(@rowset, @i)
SET @pedido = Field(@row, 'NumeroPedido')
SET @valor = Field(@row, 'ValorTotal')
SET @status = Field(@row, 'Status')
IF @status == 'Entregue' THEN
SET @resumo = Concat('Pedido ', @pedido, ' entregue - R$ ', @valor)
ENDIF
NEXT @i
ENDIF
]%%
⚠️ Atenção: Os editores visuais do SFMC (WYSIWYG) podem desfazer sua indentação ao salvar. Use blocos HTML (não de conteúdo visual) para preservar a formatação.
Comentários
O código diz como. O comentário diz por quê. - Jeff Atwood
Comentários bem escritos são tão importantes quanto o código em si. Com o tempo, você vai agradecer.
Cabeçalho do script
Para scripts longos, comece com um bloco descrevendo o propósito e a estrutura geral:
%%[
/* ─────────────────────────────────────────────────────────────────────────
E-mail de carrinho abandonado - Lojas Vitória
Lógica:
1. Busca itens do carrinho na DE Carrinho_Abandonado
2. Valida se o cliente ainda tem os itens disponíveis em estoque
3. Calcula desconto progressivo baseado em dias desde o abandono
4. Exibe cupom se desconto for aplicável
─────────────────────────────────────────────────────────────────────── */
]%%
Comentários de seção
Divida scripts longos em seções marcadas:
%%[
/* ── 1. Dados do cliente ────────────────────────────────────────── */
SET @nomeCliente = Lookup('Clientes_DE', 'Nome', 'Email', emailaddr)
SET @cpf = Lookup('Clientes_DE', 'CPF', 'Email', emailaddr)
/* ── 2. Itens do carrinho ───────────────────────────────────────── */
SET @itens = LookupRows('Carrinho_DE', 'Email', emailaddr)
SET @total = RowCount(@itens)
/* ── 3. Cálculo do desconto ─────────────────────────────────────── */
SET @diasAbandonado = DateDiff(Now(), @dataAbandono, 'D')
]%%
Comentários inline
Use para explicar decisões não óbvias - por que aquele valor, por que aquela lógica:
/* Usa AttributeValue ao invés de Lookup para capturar campos de perfil
do subscriber mesmo quando não há DE de envio configurada */
SET @email = AttributeValue('EmailAddress')
/* Limite de 3 itens por e-mail - decisão de negócio da equipe de CRM */
IF @total > 3 THEN
SET @total = 3
ENDIF
Codificação defensiva
Sempre verifique se o dado existe
Nunca assuma que um campo vai ter valor. Se o campo não existir na DE ou estiver vazio, seu e-mail pode quebrar ou enviar em branco para milhares de pessoas.
Use AttributeValue() para capturar campos de perfil com segurança, e valide com Empty() ou IsNull() antes de usar o valor:
SET @nomeCliente = AttributeValue('Nome')
IF Empty(@nomeCliente) THEN
SET @nomeCliente = 'Cliente'
ENDIF
Para Data Extensions, o Lookup() retorna vazio se não encontrar o registro - então sempre trate esse caso:
SET @segmento = Lookup('Segmentos_DE', 'Tier', 'Email', emailaddr)
IF Empty(@segmento) THEN
SET @segmento = 'Padrão'
ENDIF
Use RaiseError para dados críticos
Às vezes é melhor não enviar do que enviar errado. Se um dado é obrigatório para o e-mail fazer sentido - como um número de pedido, um CPF ou um valor de fatura - use RaiseError() para abortar o envio daquele subscriber quando o dado estiver faltando.
SET @numeroPedido = Lookup('Pedidos_DE', 'Numero', 'Email', emailaddr)
/* Se não tem número de pedido, não faz sentido enviar o e-mail de confirmação */
IF Empty(@numeroPedido) THEN
RaiseError('Número de pedido não encontrado para: ' + emailaddr, true)
ENDIF
O segundo parâmetro true faz o sistema pular esse subscriber (não aborta o envio inteiro). Use false se quiser abortar o job por completo.
💡 Dica: Durante o desenvolvimento,
RaiseError()é seu melhor amigo para identificar dados inconsistentes antes de um envio real. Habilite ele em ambiente de teste e deixe ele te mostrar onde estão os buracos.
Limite chamadas HTTP externas
Funções como HTTPGet() fazem requisições externas a cada e-mail renderizado. Em um disparo de 500 mil e-mails, isso significa 500 mil requests no seu servidor. Siga as diretrizes:
- Máximo de 3 chamadas de conteúdo externo por e-mail
- Use
%%Before;HTTPGet "url"%%para chamadas que devem ocorrer uma vez por job de envio, não por subscriber - Evite
HTTPGetdentro de loops - o número de requests cresce de forma proporcional ao tamanho do rowset
Depuração
Imprima variáveis no fluxo
Quando algo não está funcionando como esperado, a técnica mais rápida é imprimir os valores das variáveis diretamente no e-mail durante os testes:
%%[
SET @segmento = Lookup('Segmentos_DE', 'Tier', 'Email', emailaddr)
SET @pontos = Lookup('Fidelidade_DE', 'Saldo', 'Email', emailaddr)
]%%
<!-- DEBUG - remover antes de produção -->
<pre>
segmento: %%=v(@segmento)=%%
pontos: %%=v(@pontos)=%%
</pre>
Reduza até funcionar
Se o erro é difícil de identificar, remova todo o HTML e deixe só o AMPscript. Se ainda quebrar, reduza o código ao mínimo que funciona e vá adicionando de volta até reproduzir o erro. É repetitivo, mas funciona.
Valide a sintaxe antes de testar
No Content Builder, erros de sintaxe aparecem em vermelho na aba Pré-visualização e Teste - antes de você sequer mandar um e-mail de teste. Sempre abra a pré-visualização primeiro para garantir que a sintaxe está certa antes de testar com dados reais.
Modularização
Reutilize com Content Blocks
Se um trecho de AMPscript ou HTML é usado em múltiplos e-mails - um rodapé de programa de fidelidade, um bloco de status de pedido, um banner dinâmico - isole em um Content Block e referencie pelo External Key:
%%=ContentBlockByKey('bloco-status-fidelidade')=%%
Assim, qualquer ajuste no bloco se reflete automaticamente em todos os e-mails que o usam.
Content Blocks dinâmicos
Você pode calcular qual Content Block carregar com base em dados do subscriber - útil para variações por região, idioma ou segmento:
SET @regiao = Lookup('Clientes_DE', 'Regiao', 'Email', emailaddr)
SET @chaveBloco = Concat('oferta-regional-', Lowercase(@regiao))
/* Resultado: 'oferta-regional-sudeste', 'oferta-regional-nordeste', etc. */
%%=ContentBlockByKey(v(@chaveBloco))=%%
Isso mantém o template limpo e elimina uma série de IF/ELSEIF para cada variação.