Como criar uma skill no Claude Code para e-mails HTML: tabelas, CSS inline, dark mode e texto alternativo

Ilustração de uma pasta de skill do Claude Code gerando um e-mail HTML com tabelas e código inline

Fala aí, beleza? Se tu já pediu pro Claude Code um e-mail HTML e recebeu algo com cara de landing page, cheio de flex e CSS num bloco <style>, a solução é uma skill dedicada

Na prática, a skill é uma pasta com um SKILL.md em .claude/skills/<nome>/ (projeto) ou ~/.claude/skills/<nome>/ (pessoal)

Ela tem uma description que cita e-mail, newsletter e template, e um corpo com as regras que a skill genérica de UI não cobre: layout em tabela com role="presentation", CSS inline, imagens com alt, dark mode como melhoria progressiva e contraste dentro do WCAG

O cenário aqui é e-mail transacional e newsletter, bora ver na prática? 🙂

Por que a skill genérica de UI gera e-mail HTML que quebra

Porque ela foi pensada pra página web, e cliente de e-mail não é navegador

O sintoma é clássico: o Claude entrega HTML com display:flex ou grid, CSS concentrado em um bloco <style> e estrutura de página web, e aí o e-mail desmonta em parte dos clientes

E qual é a causa? Se liga nos três pontos:

  • Outlook clássico: segundo a documentação da Mailjet sobre renderização no Outlook, o Outlook clássico para Windows (2007, 2010, 2013, 2016, 2019 e o Outlook clássico do Microsoft 365) renderiza o HTML com o motor do Microsoft Word, que tem suporte limitado a HTML e CSS modernos. Já o novo Outlook para Windows usa o Microsoft Edge WebView2
  • Bloco <style>: segundo a página do elemento style no caniemail, ele tem suporte parcial no Gmail e não é suportado quando a conta não é do Google
  • Flex: o caniemail estima o suporte a display:flex em cerca de 82,93% dos clientes, com variação grande de cliente pra cliente

Tem um detalhe que confunde muita gente

A documentação de CSS do Gmail diz que dá pra estilizar com blocos <style>, que media queries por largura, orientação e resolução funcionam e que seletores de classe, elemento e id são aceitos

Só que isso não cobre contas que não são do Google, e é justamente aí que o caniemail registra a falta de suporte

Então a régua do post é o caniemail, não a doc de um cliente só

A solução é uma skill de nicho que troca o reflexo de "página web" por regras de e-mail

E pra prevenir que o problema volte, a própria skill manda conferir no caniemail antes de usar qualquer propriedade, por exemplo a página de display:grid antes de pensar em grid

O que você precisa antes de criar a skill

O básico é ter o Claude Code instalado e um projeto em que você gera e-mails, seja transacional ou newsletter

Depois tu escolhe o escopo, segundo a documentação de skills do Claude Code:

  • Projeto: .claude/skills/<nome-da-skill>/SKILL.md, bom pra versionar junto com o repositório e o time inteiro usar
  • Pessoal: ~/.claude/skills/<nome-da-skill>/SKILL.md, bom pra ter a skill em todos os seus projetos

Se ainda tá meio nebuloso o que separa skill de agente e plugin, vale dar uma olhada nas categorias do awesome-claude-code antes de seguir

Opcional: Node com o pacote npm juice, se tu for adotar um inliner de CSS (tem uma seção só pra isso mais abaixo)

Passo a passo: como criar a skill de e-mail HTML no Claude Code

A ideia é montar o SKILL.md em camadas: primeiro a estrutura, depois o gatilho, depois as regras

Os exemplos abaixo são didáticos, servem de ponto de partida pra tu adaptar ao teu projeto

1. Crie a pasta e o SKILL.md:

Uma skill é uma pasta com um arquivo SKILL.md

Esse arquivo tem duas partes: o frontmatter YAML entre marcadores ---, que diz ao Claude quando usar a skill, e o corpo em Markdown com as instruções que ele segue quando a skill roda

No escopo de projeto, a estrutura fica assim:

.claude/
  skills/
    email-html/
      SKILL.md
      reference.md
      examples.md
      scripts/

O reference.md, o examples.md e a pasta scripts/ entram nos próximos passos, pode criar só o SKILL.md agora

O erro comum deste passo: criar o arquivo solto em .claude/skills/ sem a pasta da skill. O caminho documentado é .claude/skills/<nome-da-skill>/SKILL.md

2. Escreva o frontmatter com name e description:

A description é o gatilho

O Claude compara a tarefa com as descriptions das skills pra decidir quais são relevantes, então ela precisa ser específica e ter as palavras-chave certas

Nas boas práticas de autoria de Agent Skills da Claude Platform, a description tem no máximo 1.024 caracteres e deve dizer o que a skill faz e quando usá-la

---
name: email-html
description: Gera e revisa e-mails HTML (e-mail transacional, newsletter e template de e-mail) com layout em tabela, CSS inline, texto alternativo em imagens, dark mode como melhoria progressiva e contraste WCAG. Use quando o pedido for um e-mail, uma newsletter ou um template de e-mail. Não usar para landing pages ou páginas web.
---

Repara que as palavras e-mail, newsletter, template de e-mail e e-mail transacional estão todas lá, e tem uma frase de exclusão no final

O erro comum deste passo: description vaga, do tipo "cria layouts HTML bonitos". Ela vai acionar em pedido de página web também, e aí a skill de e-mail aparece onde não devia

3. Escreva as regras de layout:

Aqui entra o PORQUÊ antes do como: o Outlook clássico renderiza com o motor do Word, então a estrutura que aguenta mais clientes é tabela, não flex nem grid

Pensa assim: se você conhece layout em tabela da web dos anos 2000, é bem semelhante, só que agora com intenção 😛

E o tal do role="presentation"? Ele avisa que a tabela é de layout e não de dados, o que ajuda leitores de tela. Segundo o caniemail, o atributo role é suportado no Apple Mail e no Gmail, e tem suporte parcial no Outlook e no Yahoo! Mail

No corpo do SKILL.md:

## Layout

- Monte a estrutura com tabelas aninhadas.
- Toda tabela de layout leva role="presentation".
- Não use display:flex nem display:grid como estrutura principal.
- Defina uma largura máxima fixa para o contêiner principal e peça para conferir a renderização nos clientes de e-mail.
- Antes de usar qualquer propriedade CSS fora desta lista, consulte a página dela no caniemail.com.

Um trecho didático do que a skill deve produzir:

<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
  <tr>
    <td align="center">
      <table role="presentation" cellpadding="0" cellspacing="0" border="0">
        <tr>
          <td style="padding: 24px; font-family: Arial, sans-serif; color: #1a1a1a; background-color: #ffffff;">
            Seu pedido foi confirmado
          </td>
        </tr>
      </table>
    </td>
  </tr>
</table>

A largura máxima depende do teu layout: define a tua e confere a renderização nos clientes de e-mail

O erro comum deste passo: deixar a regra só como "use tabelas" e esquecer de proibir flex e grid. O modelo pode misturar os dois

4. Escreva as regras de CSS:

Como o <style> não funciona em contas que não são do Google, o estilo que precisa aparecer vai inline, no atributo style

O bloco <style> fica só pra media queries, que são melhoria, não base

E como uma media query sobrescreve um estilo inline? Com !important. O caniemail tem uma página só pra palavra-chave !important, vale conferir antes

## CSS

- Todo estilo necessário para o e-mail ficar legível vai inline, no atributo style.
- O bloco <style> só pode conter media queries.
- Dentro das media queries, use !important para sobrescrever o estilo inline.
- O e-mail precisa continuar legível se o bloco <style> for ignorado.

O erro comum deste passo: colocar cor de texto ou fundo só no <style>. Em conta não Google isso some, e o e-mail perde a aparência inteira

5. Escreva as regras de imagem:

Imagem pode não carregar, e quem usa leitor de tela depende do texto alternativo pra entender o conteúdo

## Imagens

- Toda imagem de conteúdo tem alt descritivo (o que ela comunica, não "imagem").
- Imagem decorativa tem alt vazio: alt="".
- Informação importante (preço, código, data, link de ação) vai em texto HTML, nunca só dentro da imagem.
- Consulte a página de <img> no caniemail.com antes de usar atributos fora do básico.

A referência pra isso é a página de img no caniemail

O erro comum deste passo: botão de "Confirmar pedido" feito como imagem, com o texto só dentro dela. Se a imagem não carrega, o leitor fica sem a ação principal do e-mail

6. Escreva as regras de dark mode:

Dark mode em e-mail é melhoria progressiva, não fundação

O caniemail estima o suporte a @media (prefers-color-scheme) em cerca de 41,86% dos clientes

Na página: Apple Mail com suporte, Gmail sem suporte e Outlook com suporte parcial, sendo que em algumas versões a query é reescrita (por exemplo para @media ( _filtered_a ) ou @media none)

Ou seja, em boa parte dos clientes a tua regra de dark mode simplesmente não roda

## Dark mode

- O e-mail precisa ser legível sem nenhuma regra de dark mode.
- Regras de dark mode ficam em @media (prefers-color-scheme: dark), com !important.
- Antes de usar a propriedade CSS color-scheme ou a meta tag color-scheme, confira o suporte no caniemail.com.

Um exemplo didático do bloco:

<style>
  @media (prefers-color-scheme: dark) {
    .corpo { background-color: #1a1a1a !important; color: #f2f2f2 !important; }
  }
</style>

Antes de escrever a regra, confere no caniemail as páginas da propriedade color-scheme e da meta tag color-scheme

O erro comum deste passo: depender do dark mode pra o texto ficar legível. Se o cliente ignora a media query, o leitor fica com a versão base, então ela tem que funcionar sozinha

7. Escreva as regras de contraste e organize os arquivos:

O WCAG 1.4.3 (Contraste mínimo) exige pelo menos 4,5:1 pra texto normal e 3:1 pra texto grande

Texto grande é 18pt normal ou 14pt negrito, logotipos e texto puramente decorativo ficam de fora, e os valores não podem ser arredondados

## Contraste

- Texto normal: contraste de pelo menos 4,5:1 com o fundo.
- Texto grande (18pt normal ou 14pt negrito): pelo menos 3:1.
- Não arredonde a razão de contraste.
- Confira o contraste na versão clara e na versão escura.

## Referências

- Detalhes de suporte por propriedade: reference.md
- Trechos prontos de e-mail transacional e newsletter: examples.md

A documentação do Claude Code recomenda manter o SKILL.md com menos de 500 linhas e mover o material detalhado pra arquivos separados, como reference.md e examples.md, citados a partir do SKILL.md

No reference.md tu guarda as consultas que fez no caniemail, com o link de cada página, e o SKILL.md fica só com as regras

O erro comum deste passo: colar no SKILL.md tabela de suporte de cada cliente, trecho de template e tudo mais. O arquivo incha e as regras importantes se perdem no meio

Como evitar que a skill de e-mail roube pedidos de landing page

Com description específica, que fala de e-mail e exclui página web

O motivo: se as descriptions forem vagas ou se sobrepuserem, o Claude pode carregar a skill errada ou deixar de usar a certa, e a skill genérica de UI e a de e-mail vivem no mesmo território (HTML e layout)

Olha o contraste:

# Ruim: casa com qualquer pedido de HTML
description: Cria layouts HTML responsivos e bonitos.

# Boa: fala de e-mail e exclui página web
description: Gera e revisa e-mails HTML (e-mail transacional, newsletter e template de e-mail) com layout em tabela e CSS inline. Use quando o pedido for um e-mail, uma newsletter ou um template de e-mail. Não usar para landing pages ou páginas web.

Pra fechar a porta da colisão:

  1. Coloque e-mail, newsletter, template de e-mail e e-mail transacional na description
  2. Escreva a frase de exclusão: "Não usar para landing pages ou páginas web"
  3. Se a colisão continuar, adicione disable-model-invocation: true no frontmatter. Assim o Claude não chama a skill por conta própria, e ela só roda quando tu digita /email-html
---
name: email-html
description: Gera e revisa e-mails HTML (e-mail transacional, newsletter e template de e-mail). Não usar para landing pages ou páginas web.
disable-model-invocation: true
---

O erro comum desta seção: usar só palavras genéricas como "layout" ou "HTML responsivo" sem a palavra e-mail. É exatamente o vocabulário de um pedido de landing page

Quando usar um inliner de CSS em vez de uma regra em texto

Quando a regra é determinística

"Mova todo o CSS pra inline" não precisa de julgamento, é transformação mecânica, e transformação mecânica é melhor executada por script do que confiada ao modelo

É como pedir pra alguém copiar uma planilha à mão em vez de usar Ctrl+C: dá pra fazer, mas uma hora escapa uma célula…

O Juice faz isso: é uma biblioteca que transfere as propriedades CSS pro atributo style dos elementos HTML, pensada pra e-mail HTML

Ela tem API pra strings, arquivos e DOM do cheerio, além de uma CLI, licença MIT, e o pacote npm se chama juice

Como encaixar na skill:

  1. Crie o script de inlining dentro de scripts/, seguindo a API ou a CLI descrita no README do repositório (os parâmetros exatos estão lá, não vale chutar flag)
  2. Cite o script no SKILL.md, dizendo quando rodar: depois de gerar o HTML e antes de entregar
  3. Se quiser que o Claude rode a ferramenta sem pedir aprovação a cada uso, liste-a em allowed-tools no frontmatter. Isso vale só enquanto a skill está ativa e não amplia as permissões fora dela

Os scripts são executados, não carregados no contexto, então o código do inliner não ocupa espaço nas instruções da skill

Um trecho didático de como fica a instrução no corpo:

## CSS inline

- Escreva o CSS no bloco <style> de forma organizada.
- Depois de gerar o HTML, rode o script de scripts/ para mover o CSS para inline.
- Mantenha no <style> apenas as media queries.

O erro comum desta seção: manter a regra "escreva tudo inline" E rodar o inliner. Tu duplica o trabalho e cria conflito entre o que o modelo escreveu inline e o que o script injeta. Escolha um caminho: ou regra em texto, ou script

Como testar a skill na sessão do Claude Code

Testando os dois caminhos de invocação e conferindo o HTML gerado

O Claude usa a skill sozinho quando ela é relevante, e tu também pode chamá-la direto com /nome-da-skill

  1. Chame direto: /email-html com um pedido de e-mail transacional de confirmação de pedido
  2. Teste a invocação automática: peça uma newsletter sem citar a skill e veja se ela é usada
  3. Teste a exclusão: peça uma landing page e confirme que a skill de e-mail não aciona
  4. Revise o HTML com o checklist abaixo

Checklist do HTML gerado:

  • Estrutura em tabelas aninhadas
  • role="presentation" em toda tabela de layout
  • Estilos necessários inline, no atributo style
  • <style> só com media queries, usando !important
  • alt descritivo em toda imagem de conteúdo e alt="" nas decorativas
  • Nenhum flex ou grid como estrutura principal
  • Contraste de pelo menos 4,5:1 no texto normal e 3:1 no texto grande
  • E-mail legível sem as regras de dark mode

Tome cuidado: passar no checklist não é o mesmo que renderizar bem

O checklist confere se a skill seguiu as regras, mas a renderização real só se confirma abrindo o e-mail nos clientes que o teu público usa, Outlook clássico incluso

Vídeo: o processo de criar skills para Claude Code

No vídeo abaixo tem o processo geral de criação de skills pro Claude Code, passo a passo, que ajuda a montar o SKILL.md e pensar na description como gatilho

Vídeo trata do processo geral de criação de skills para Claude Code (passo a passo), o que ajuda a contextualizar a metodologia de escrever um SKILL.md com frontmatter e description-gatilho mencionada no artigo. Não aborda especificamente e-mail HTML, CSS inline, tabelas ou dark mode.

Próximo passo: transformar a skill em padrão do time

Se tu começou no escopo pessoal, o próximo passo é mover a pasta pra .claude/skills/email-html/ dentro do repositório, assim todo mundo do time gera e-mail com as mesmas regras

Versiona junto o reference.md com os links das consultas ao caniemail

E revisa essas regras de tempos em tempos: suporte de cliente de e-mail muda, e o número que vale hoje pode não valer amanhã

O mesmo raciocínio serve pra qualquer saída em que a skill genérica falha, tipo uma revisão de código com critérios do teu time

Escolhe o próximo tipo de saída que te dá dor de cabeça e monta a skill dele 😀

até o próximo post!

Quer aprender mais sobre inteligência artificial e programação na prática? Conheça o canal Hora de Codar no YouTube e acompanhe os próximos vídeos.

Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Vibe Coding

Formação Vibe Coding

Do Prompt ao Produto: Crie Software Real com IA

  • 474 aulas
  • 20 projetos
  • 39h 30min

Blog | Mais populares