# Receita: E-mail > Framework web para Go no estilo Next.js: uma pasta em app/ é uma rota, o HTML é escrito em Go e nada fora da biblioteca padrão é importado. > /trilha/pt/llms/recipes/email.txt - [E-mail](/trilha/pt/receitas/email): trilha/mail — o corpo é h.Node, o texto se escreve sozinho, o dev escreve .eml e um teste afirma sobre o que foi enviado sem servidor nenhum. · 2157 tokens est. 1 page(s) · 2157 tokens est. in all --- Mandar e-mail são três problemas usando um casaco só: falar com um servidor, montar uma mensagem válida e não mandar nada de dentro de um teste. O `trilha/mail` responde os três, e o que vale ler é quais decisões ele tira de você. ## Ou: `trilha add mail` ```bash trilha add mail --dry-run ``` ```text + internal/correio/correio.go + internal/correio/correio_test.go --dry-run: nada foi escrito ``` Dois arquivos e nenhuma tela — o `mail` não tem listagem nem rota, então não toca o `app/setup.go`. O que chega é o `internal/correio/correio.go`: a variável `Mailer` abaixo, já construída a partir de `mail.FromEnv()`, e um teste que prova isso contra o `mail.Outbox` sem rede. O que esta página soma é tudo o que a receita não pode decidir por você: a mensagem em si, o `mail.Layout` e o `mail.Button`, o fluxo de convite, e como trocar de provedor pelo `Transport`. Rode a receita pelo arquivo que é dono do `Mailer`; escreva as mensagens aqui, porque uma receita não tem como adivinhar o que o seu app tem para dizer. ## O remetente ```go // Mailer is the one an app holds: built once, at startup, from the // environment. New opens no connection and reads no file, so it belongs in a // var and not behind a sync.Once. var Mailer = mail.New(mail.FromEnv()) ``` O `FromEnv` lê uma variável: ```bash TRILHA_MAIL_URL='smtp://usuario:senha@smtp.org.br:587?from=Acervo ' ``` A porta 587 é STARTTLS; a 465 (ou `smtps://`) é TLS implícito. Com a variável vazia o comportamento depende de onde o app está rodando, e é essa diferença que importa: em dev ele escreve `.eml` em `./mail` e diz onde; em qualquer outro lugar o `Send` devolve `mail.ErrNotConfigured`. A assimetria é de propósito. Um app em produção que arquiva convites numa pasta caladinho é um app cujos usuários nunca são convidados, e ninguém descobre por uma semana. ## Enviando ```go // SendWelcome is what a handler calls. The message is an h.Node — the same // nodes the pages are written with — and mail.Layout is what keeps the tables // and the inline CSS out of here. func SendWelcome(c *trilha.Ctx, nome, email, link string) error { return Mailer.Send(c.Context(), mail.Message{ To: []string{email}, Subject: "Sua conta está pronta", Body: mail.Layout("Acervo", h.P(h.Textf("Olá, %s.", nome)), mail.Button("Definir minha senha", link), mail.Muted(h.Text("O link vale por uma hora.")), ), }) } ``` O `mail.Layout` é uma tabela centralizada, com larguras em pixels e toda regra inline, porque o Outlook renderiza com o Word — sem flexbox, sem grid, sem float — e o Gmail arranca o `