-
Notifications
You must be signed in to change notification settings - Fork 1
EmailRealizer pt BR
🌐 Esta página em: English · Português
Estado: o núcleo está CONSTRUÍDO (merge em 2026-08-25; sai no próximo release).
EmailRealizereEmailRendererexistem emeQuantic.UI.Emailcom o vocabulário abaixo. Ainda à frente: a matriz de clientes reais (um sample gerado contra Gmail/Outlook/Apple Mail) e os pins de HTML quando a saída assentar.
Escrever o email em C# com os mesmos componentes com que se escreve uma página, e receber de volta um HTML que um cliente de email realmente renderiza.
Um componente aqui é uma árvore de VisualNode que não sabe nada sobre seu alvo. O realizador web a
transforma em DOM e CSS; o Photon a transforma em pintura na GPU. Email é um terceiro realizador
— um alvo cujo motor de render é muito restritivo, o que é arquiteturalmente a mesma forma de um
alvo sem DOM nenhum.
Nada na camada de autoria muda. Os mesmos Column, Text, Image e tokens de tema, o mesmo
Build(context).
Duas peças estão na árvore hoje, verificadas lendo o código:
-
WebRealizer.Lower(node, theme, typeScale, styles: null)— sem o sink de estilos, os estilos ficam inline no elemento em vez de virarem classes atômicas deduplicadas. Estilo inline é a restrição mais dura do email, e esse caminho já o produz. -
HtmlRenderer.RenderNode(...)transforma a árvore rebaixada numa string de HTML.
Ou seja, "componente C# → HTML com estilos inline" são duas chamadas que já existem. O que falta é tudo o que diz respeito ao meio.
| Exigência | Por quê | Onde o realizador web difere |
|---|---|---|
Layout em <table> aninhada |
O Outlook no Windows renderiza com o motor do Word: sem flexbox, sem grid |
Row/Column descem para FlexDirection
|
Só style="" inline |
Blocos <style> e CSS externo são removidos ou ignorados por vários clientes |
Classes atômicas + folha de estilo (o caminho do sink) |
| Cores literais | Custom properties do CSS não são resolvidas | Tokens emitem var(--eq-color-…, fallback)
|
| URL absoluta de imagem ou CID | URIs data: são descartadas pelo Gmail |
Assets assumem uma origem servida |
| Largura restrita | ~600px é a convenção que todo cliente tolera | Páginas são fluidas |
| Nenhuma interação | Sem JS, sem hover na maioria dos clientes, sem contêiner rolável |
Pressable, ScrollView e estados de hover existem |
Um pacote novo, eQuantic.UI.Email, dependendo apenas de Primitives e Core — nunca de
eQuantic.UI.Web, para que os dois realizadores não possam derivar um para dentro do outro.
// Escrito exatamente como uma página.
public sealed class WelcomeEmail(string name) : StatelessComponent
{
public override VisualNode Build(ComponentContext context) =>
Column(gap: Space.S4, children: [
Image(Assets.Logo, width: 132),
Text($"Bem-vindo, {name}", TypeRole.Heading),
Button("Confirme seu endereço", href: "https://…"),
]);
}
// Renderizado onde é enviado.
EmailMessage message = EmailRenderer.Render(new WelcomeEmail("Edgar"), theme);
// message.Html — rebaixado para tabelas, totalmente inline
// message.PlainText — gerado da MESMA árvore, não escrito duas vezesEmailMessage carrega as duas partes porque uma mensagem multipart precisa das duas, e gerar a
alternativa em texto a partir da árvore é o único jeito de ela ficar em dia com o HTML.
M0 — Medir antes de construir. Feita — e mudou o plano. Além dos dois achados esperados
(layout flex, cores light-dark()), um terceiro que o plano não tinha: a tipografia vive nas
classes eq-type-*, e um email não tem folha de estilos, então todo texto saía num tamanho só. A
M2 cresceu para inlinar a rampa do tema em cada texto. A metade restante da M0 é humana: o sample
gerado contra caixas de correio reais.
M1 — Rebaixar para tabelas. Feita. Box, Row, Column e Gap viram <table>/<tr>/<td>
aninhados, com padding de célula e linhas espaçadoras. Alinhamento mapeia para align/valign. É o
grosso do track.
M2 — Estilos inline e tema literal. Feita (mais a rampa de tipo inlinada). Reusar o caminho sem sink; resolver todo token para uma cor e um comprimento literais, para nada depender de custom properties. Densidade e escala de tipo resolvem uma vez, na renderização.
M3 — Casca do documento. Feita. EmailDocument: doctype, o conjunto de <meta>, o contêiner de 600px,
a linha invisível de preheader, e o meta de modo escuro que os clientes honram.
M4 — Cerca do vocabulário. Feita. Diagnósticos nomeando o que um email não faz — ScrollView,
Pressable, Draggable, estilo de hover e foco, position: absolute. Um Link vira <a>; um
Button vira um <a> à prova de balas estilizado como botão. Uma Image sem URL absoluta é um
erro, não uma figura quebrada na caixa de entrada de alguém.
M5 — Alternativa em texto puro. Feita. Percorrer a mesma árvore para a parte text/plain.
A fatia passou por cinco rondas de revisão (32 achados) e o que sobreviveu são regras que valem ser ditas:
-
Propriedade que o meio não expressa é cercada, não aproximada: tinta em gradiente e
MaxLinesatiram nomeando a saída — um sólido no lugar é outra tinta que ninguém escolheu, e mostrar mais texto do que o autor limitou é divergência de conteúdo. -
Propriedade que o meio expressa diferente é honrada: padding de contêiner (tabela-envelope de
uma célula),
CrosseAlignSelfpor filho (alinhamento da célula), raios por canto, bordas, elementos de heading,aria-labeldoLink.Label. -
MainAligné vácuo aqui, documentado em vez de cercado: uma tabela de email dimensiona-se ao conteúdo, então não há espaço livre a distribuir — todo valor renderiza igual, o que é fiel. -
Um componente quebrado falha o ENVIO. Componentes expandem via
Build, não oBuildContaineddo web: uma caixa de erro é certa numa página viva que um developer está olhando e errada numa mensagem prestes a chegar à caixa de entrada de um leitor vestida de conteúdo. -
Endereços são parseados, não checados por prefixo; valores de atributo são codificados; um
Linkem volta de runs com link recusa aninhar âncoras, nomeando a escolha.
-
Nunca um bloco
<style>, mesmo onde um cliente o suporte. Uma regra vence uma matriz de exceções. - Sem interatividade. Um email é uma página impressa que por acaso tem links.
- Sem gambiarra por cliente dentro dos componentes. O que o Outlook precisa mora no realizador, nunca em algo que um autor escreve.
- Anexos e envio não são nossos. A saída é HTML mais texto; enviar é trabalho da app (MailKit, SES, o que ela já usa).
As mesmas duas redes que o resto do framework usa:
- Pins de HTML, regenerados de propósito como as fixtures transpiladas, para que uma mudança de layout apareça como diff e não como surpresa.
- Uma matriz de clientes como conformidade, rodada contra clientes reais e registrada — a regra do "o browser é o árbitro" vale aqui ainda mais forte, porque clientes de email estão mais longe de uma especificação do que browsers estão.
🌐 English · Português
🏁 Comece aqui
📱 Write-once
- Componentes write-once
- Superfície declarativa
- Motor Photon
- Design System
- Capacidades
- Armazenamento
- Formulários
- Editor de código
- Markdown
- Mermaid
- Renderização de Email
🏗️ Arquitetura
⚙️ Compilação
- Compilador
- Avaliação em tempo de compilação
- Recursos C# suportados
- Resolução de tipos externos
- Fluxo de build
- Diagnósticos
⚡ Runtime
🔌 Servidor
🎨 Ecossistema
🚀 Desenvolvimento