Documentação

Comunicações

Enviar e-mail e SMS pelos seus próprios provedores, e por que o seu código nunca nomeia um.

O seu código nomeia um template e um idioma. Ele nunca nomeia um provedor, um assunto ou um corpo. Essa indireção é o desenho inteiro, e tudo abaixo decorre dela.

await nulvless.comms.email.send({
  to: '[email protected]',
  template: 'grants-invite',
  language: 'pt-BR',
  params: { organization: 'Acme Inc', role: 'admin' },
});

Trocar de provedor, reescrever o texto, adicionar um idioma — nada disso toca nesta chamada.

Traga o seu provedor

As mensagens saem pelas suas contas, não pelas nossas. Cada ambiente configura as dele, e cada provedor é habilitado de forma independente:

emailprovedor
direct_smtpQualquer servidor SMTP — host, porta, usuário, senha de app.
googleGoogle Workspace.
send_gridSendGrid, por chave de API.
mailtrapMailtrap — a escolha óbvia para um ambiente de desenvolvimento.
smsprovedor
twilio
vonage

Como o provedor é por ambiente, desenvolvimento pode apontar para o Mailtrap enquanto produção aponta para o SendGrid — com os mesmos slugs de template e o mesmo código chamando. Um teste não chega numa caixa de entrada real por configuração, não porque alguém lembrou de proteger a chamada.

Verifique a ligação antes de um usuário depender dela:

await nulvless.comms.email.test('[email protected]');

Vale rodar do seu pipeline de deploy contra um ambiente novo. Um provedor mal configurado é invisível até a primeira pessoa precisar de um código de verificação.

A plataforma também manda mensagens

Códigos de confirmação, links de recuperação, convites — a plataforma envia tudo isso pelos mesmos provedores e pelos mesmos templates. Todo ambiente já começa com o conjunto de que precisa, e cada um é editável:

welcome-user · email-otp-verification · email-link-verification · email-otp-enable-mfa-request · change-email-identity · reset-password-email · grants-invite

E para SMS: phone-otp-verification · phone-link-verification · phone-otp-enable-mfa-request · change-phone-identity

É por isso que o e-mail de cadastro chega na voz da sua marca sem você escrever código de envio — e por isso quebrar um desses templates quebra o cadastro.

Um template é por canal. As versões de e-mail e SMS da mesma ideia são slugs separados, porque um texto que funciona numa caixa de entrada não sobrevive a 160 caracteres. Editar email-otp-verification não faz nada com phone-otp-verification.

Editar grava a sua versão, não por cima da nossa

Os padrões da plataforma não são registros seus, então editar não os modifica. Salvar grava a sua versão para aquele canal, slug e idioma, e o envio prefere ela:

a sua versão no idioma pedido
  ↓ não existe
o padrão da plataforma

Duas consequências. Apagar a sua versão é como se volta ao padrão — não há nada para restaurar, porque o padrão nunca foi sobrescrito. E como os padrões vêm só em inglês, um projeto sem versão em português de welcome-user envia a inglesa em vez de falhar.

Adicionar um idioma é aditivo pelo mesmo motivo: welcome-user em pt-BR é um registro separado, e escrevê-lo não toca no de inglês.

O envio é enfileirado

A chamada publica uma mensagem; um worker entrega. Uma chamada que resolve sem erro significa aceita para entrega, não entregue.

Isso tem uma consequência que vale considerar no desenho: falhas de entrega não voltam para você. Elas são gravadas na mensagem, com um código:

template_not_foundentrega

O slug não existe para aquele canal e idioma.

missing_template_parametersentrega

O template esperava params que você não passou.

disabled_featureentrega

O ambiente não permite o template que foi nomeado.

cannot_sendentrega

O provedor rejeitou.

Então um template que referencia {{ organization }} quando você não mandou nenhum não falha no ponto de chamada — falha minutos depois, em silêncio, a menos que você leia o histórico da mensagem. Trate params como contrato.

Idioma

O language escolhe a variante. Omita e vale o padrão do ambiente.

O envio resolve isso em três passos, e vale conhecer o último:

o idioma que você pediu1

Usado quando existe uma versão para ele.

inglês2

O fallback, e onde vivem os padrões da plataforma.

a versão mais antiga daquele template3

Último recurso quando nenhuma das duas existe — então uma mensagem pode sair num idioma que ninguém pediu.

Esse terceiro passo vale só para templates que você criou: se você escrever order-shipped só em pt-BR e depois enviar em es-ES, sai o português. Escreva também a versão em inglês se preferir que isso nunca aconteça.

Defina uma vez no client, em vez de a cada chamada:

createClient(url, key, { language: () => navigator.language });

É uma função para poder ser resolvida por requisição em vez de congelada na construção — o que importa num servidor atendendo usuários em locais diferentes.

Template é uma tripla

Tudo exceto create e list endereça um template por canal + slug + idioma:

await nulvless.comms.templates.get('email', 'welcome-user', 'pt-BR');
await nulvless.comms.templates.update('email', 'welcome-user', params, 'pt-BR');

Não há id para guardar. O mesmo slug em dois idiomas são dois registros, e é isso que faz adicionar um idioma ser aditivo em vez de uma migração.

O terceiro canal

Além de e-mail e SMS, um template pode ser um webhook: em vez de renderizar uma mensagem para uma pessoa, ele posta numa url sua. O ponto de chamada é idêntico, então uma notificação pode migrar de e-mail para webhook por configuração — útil para levar algo ao Slack ou ao seu próprio serviço sem tocar no código que dispara.

Limites de taxa

Envios têm cota por canal e por ambiente. Esgotar uma responde 429 rate_limit_exceeded.

O SMS também tem um intervalo mínimo por número: por padrão, um número recebe no máximo um SMS a cada 60 segundos. Um segundo envio dentro dessa janela responde o mesmo 429. Altere esse valor, ou use 0 para desativar, nos limites de taxa de comunicações do ambiente.

Diferente do serviço de auth, este não manda retryAfter — e o SDK não exporia mesmo assim. Use o seu próprio backoff em vez de ler um campo que não está lá.

Próximos

Nesta página