Módulo Notification (e-mail) — visão geral
Não existe um módulo NestJS único chamado "Notification". O que existe é uma infraestrutura de
envio de e-mail compartilhada (shared/module/email) — um contrato genérico de "enviar uma
mensagem" com duas implementações (SMTP e SES) — que cada domínio do backend usa à sua própria
maneira, com seu próprio conteúdo e sua própria rota (quando há uma). Esta seção reúne a
infraestrutura compartilhada e a única capacidade de envio de e-mail deste levantamento que tem
rota HTTP própria: o envio de laudo por e-mail, no domínio de diagnóstico.
Sobre o legado. Os cards de negócio do funil de Notification (Bitrix, ex.: F-S02, F-S03) descrevem o sistema antigo (
mm-pacs-portal-api/core/services/emailServiceOld.js): envio via Mailgun, templates HTML por idioma resolvidos pelo país da empresa, registro emtb_fila_email, data de nascimento do paciente na URL do link de entrega, nome do paciente no assunto. Nenhum desses cards tinha o campo de correspondência "status vs código real" preenchido — trate-os como especificação de legado, não como verdade do código atual. O código atual (branchintegration/with-fixlaudo) é uma reescrita bem mais simples: sem Mailgun, sem template por país/idioma, sem fila de e-mail própria (o outbox existente é o de auditoria, não de e-mail) e sem data de nascimento na URL. O envio de laudo por e-mail manteve, do legado, apenas o comportamento de sempre incluir o e-mail do paciente como destinatário (ver Enviar laudo por e-mail, RN-01).
Infraestrutura compartilhada (shared/module/email)
EmailModule (@Global(), registrado via forRoot() em cada app) expõe um único provider para o
token MailSender, escolhido em runtime pelo transport da config (EmailTransport.SMTP ou
EmailTransport.SES, default SES). O código de domínio nunca depende de SMTP ou SES
diretamente — só do contrato abstrato:
tsexport abstract class MailSender {abstract send(message: EmailMessage): Promise<void>;}
EmailMessage é o único formato de mensagem aceito. Campos: to (string única — não existe
cc, bcc nem attachments), subject (obrigatório, até 255 caracteres, sem quebra de
linha), e text ou html (pelo menos um dos dois, cada um entre 1 e 1.000.000 de
caracteres). Um destinatário por EmailMessage; enviar para vários endereços é sempre um laço no
código chamador, um send() por destinatário — não há envio em lote nativo.
Envio é síncrono, sem fila e (quase) sem retry
Diferente do módulo de auditoria, não há fila/outbox para e-mail. Cada mailSender.send(...)
é uma chamada síncrona, feita inline dentro do caso de uso que está processando a requisição HTTP.
Se o provedor falhar, SmtpMailSender e SesMailSender capturam o erro, logam e relançam como
InfrastructureError (errorCode: EMAIL_DELIVERY_UNAVAILABLE, HTTP 503). O único retry existente
é o retry interno do SDK da AWS para SES, configurável via EMAIL_MAX_ATTEMPTS (default 3); o
transporte SMTP não tem nenhum retry — falhou, propagou o erro.
Não há verificação de "e-mail já enviado" em nenhum dos consumidores conhecidos: repetir a mesma chamada reenvia o e-mail.
Consumidores conhecidos
| Domínio | Uso | Conteúdo/template | Documentado em |
|---|---|---|---|
identity | Convite de acesso, e-mail concedido a admin de organização, verificação de e-mail, redefinição de senha, confirmação de e-mail de recuperação, aviso de senha alterada | IdentityEmailTemplateCatalog + MobilemedEmailRenderer (HTML com logo, botão de ação, nota de expiração, PT-BR/EN/ES) — exclusivo do identity, instanciado como classe simples (new IdentityEmailTemplateCatalog()), fora do DI do Nest | Senha, Convites — a concessão de acesso de admin (accessGranted, em provision-identity-tenant-root-access.service.ts) não tem página própria localizada neste levantamento; A confirmar — responsável: time de Identity; data: 24/09/2026. |
diagnosis/report | Envio do laudo/imagens do exame por e-mail | HTML inline simples, fixo em português, sem i18n, montado no próprio serviço | Enviar laudo por e-mail (rota HTTP própria) |
IdentityEmailTemplateCatalog, apesar de estar fisicamente em package/identity/shared/email,
não é usado fora do identity — o diagnóstico monta seu próprio HTML e não passa pelo catálogo
nem pelo MobilemedEmailRenderer. Não foi encontrado nenhum outro domínio que envie e-mail neste
levantamento.
Variáveis de ambiente da infraestrutura de e-mail
Cada app (identity, diagnosis, audit...) resolve essas variáveis no seu próprio escopo — os valores podem ser diferentes por app.
| Variável | Uso | Default |
|---|---|---|
EMAIL_TRANSPORT | smtp ou ses — escolhe a implementação de MailSender | ses |
EMAIL_FROM | Remetente (from) usado em ambos os transportes | — (obrigatório) |
EMAIL_SMTP_HOST / EMAIL_SMTP_PORT / EMAIL_SMTP_SECURE | Conexão SMTP | — |
EMAIL_SMTP_USERNAME / EMAIL_SMTP_PASSWORD | Autenticação SMTP (devem vir juntas) | — |
EMAIL_SMTP_CONNECTION_TIMEOUT_MS | Timeout de conexão SMTP | — |
EMAIL_REGION (ou AWS_REGION) | Região do SES | — |
EMAIL_ACCESS_KEY_ID / EMAIL_SECRET_ACCESS_KEY (ou AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY) | Credenciais do SES (devem vir juntas) | — |
EMAIL_ENDPOINT | Endpoint alternativo do SES (ex.: para teste local) | — |
EMAIL_MAX_ATTEMPTS | Tentativas internas do SDK da AWS para SES | 3 |
Limitações confirmadas no código atual
- Sem
cc,bccou anexos em nenhum ponto do fluxo — inclusive o e-mail de laudo envia apenas links (imagens e laudo), nunca o PDF/HTML anexado. - Sem fila/outbox própria de e-mail; o outbox existente no repositório é o de auditoria
(
DiagnosisAuditOutboxRecorder), usado para registrar o evento de que um e-mail foi disparado, não para desacoplar o envio em si. - Sem idempotência: nada impede reenviar o mesmo e-mail várias vezes.
Páginas deste módulo
| Página | Cobre |
|---|---|
| Enviar laudo por e-mail | POST /exams/:id/report-emails e POST /exams/report-emails — único envio de e-mail deste levantamento com rota HTTP própria |
Os demais consumidores de e-mail (identity) já têm suas rotas documentadas nos módulos Authentication e Usuário; esta página de visão geral existe para explicar a infraestrutura que todos eles compartilham, não para duplicar aquele conteúdo.