Saltar para a documentação
SDK

Enviar um email

`emails.send`: uma mensagem, agora ou mais tarde.

emails.send

send-email.ts
const email = await openemail.emails.send({  from: { email: '[email protected]', name: 'Acme Billing' },  to: ['[email protected]', 'Grace <[email protected]>'],  cc: '[email protected]',  bcc: [{ email: '[email protected]' }],  replyTo: '[email protected]',  subject: 'Your September invoice',  html: '<p>Invoice attached.</p>',  text: 'Invoice attached.',  headers: { 'X-Campaign': 'invoices' },  attachments: [{ filename: 'invoice.pdf', content: pdfBytes }],  threadId: 'thread_…',  scheduledAt: 'PT1H',  tags: { order: '4021' },  tracking: { opens: true, clicks: true },})

to, cc e bcc aceitam um ou vários destinatários, e um único é envolvido num array automaticamente. Cada um pode ser um endereço simples, Name <addr@host> ou { email, name }.

Parâmetros

fromRecipientInputobrigatório
O remetente. Um endereço simples, `Name <addr@host>`, ou um objeto. Tem de ser um a partir do qual esta chave possa enviar. Não há remetente alternativo, porque a alternativa seria o endereço predefinido do espaço de trabalho, que muda à medida que os endereços vão e vêm.
toRecipientInput | RecipientInput[]obrigatório
Um ou vários destinatários; um único é envolvido num array automaticamente. No máximo 50 no total de to, cc e bcc.
ccRecipientInput | RecipientInput[]
Conta para o limite de 50 destinatários.
bccRecipientInput | RecipientInput[]
Nunca aparece nos bytes que qualquer outra pessoa recebe, porque é transmitido um envelope por destinatário.
replyToRecipientInput
Um único endereço, enviado como cabeçalho Reply-To.
subjectstring
No máximo 998 caracteres, o limite de linha do RFC 5322. Vazio por predefinição.
htmlstring
É obrigatório um de html, text, draftId ou template. O HTML é o que os destinatários veem quando html e text são ambos fornecidos.
textstring
A parte em texto simples.
template{ id, version?, props?, slots? }
Renderizar um modelo guardado no servidor. `version` fixa a versão; omita-o para usar a que estiver publicada quando o pedido for aceite. Uma prop desconhecida ou em falta dá 422 em vez de um espaço em branco na mensagem.
draftIdstring
Enviar um rascunho guardado com este envelope.
headersRecord<string, string>
`X-*`, `List-*`, Reply-To, Precedence, Auto-Submitted, Importance, Priority e Feedback-Id. Tudo o que o transporte define por si próprio é recusado em vez de ser descartado silenciosamente.
attachmentsAttachmentInput[]
`{ filename, content, contentType? }` ou `{ fileId }`, que refere um ficheiro já existente no espaço de trabalho. Passe bytes em content e são codificados em base64 automaticamente. 20 ficheiros, com os ficheiros inline limitados a 5 MB no total depois de descodificados. Um ficheiro guardado pode ser maior e segue como ligação de transferência.
attachmentDeliveryAttachmentDeliveryMode
`mime`, `link` ou `auto`. `auto` envia os ficheiros como ligações de transferência quando ultrapassam 2 MB num domínio com um domínio de ficheiros ativo, e dentro da mensagem nos restantes casos. Se for omitido, aplica-se a definição da caixa de correio, cuja predefinição é `auto`.
threadIdstring
Responder numa conversa existente. O transporte escreve In-Reply-To e References.
scheduledAtDate | string
Um Date, um instante ISO-8601 ou uma duração como `PT1H`. Até um ano à frente, nunca no passado. Não pode ser combinado com cancellableForSeconds.
cancellableForSecondsnumber
De 0 a 900. Uma janela para anular num envio imediato: o mecanismo de anulação do editor de mensagens, exposto em vez de fixo no código.
tagsRecord<string, string>
Até 10 etiquetas, devolvidas e filtráveis. Nunca interpretadas.
signatureboolean
Indica se esta mensagem inclui a assinatura do endereço a partir do qual é enviada, que é a assinatura própria desse endereço ou, na falta dela, a definida para Todos os endereços. A predefinição é true, porque uma assinatura pertence ao endereço e não ao cliente que enviou a mensagem. Defina `false` para o correio que um programa envia em nome de alguém, como um recibo, uma reposição de palavra-passe ou um resumo, nenhum dos quais deve levar a despedida de uma pessoa.
tracking{ opens?, clicks? }
Indica se deve ser adicionado um píxel de abertura e se as ligações desta mensagem devem ser reescritas. Ativo a menos que o proprietário do espaço de trabalho tenha desativado o rastreio para o endereço a partir do qual é enviada ou para Todos os endereços, e qualquer um dos campos indicados aqui decide para essa mensagem, independentemente da definição do endereço.
translate{ to, from?, subject?, includeOriginal? }
Enviar na língua do destinatário. `to` aceita um código, um nome em inglês ou o nome da língua na própria língua; `subject` e `includeOriginal` são ambos true por predefinição. Resolvido quando o pedido é aceite, pelo que uma mensagem agendada leva as palavras que foram aprovadas. Recusado em conjunto com `draftId`.

Resposta

idstring
O id do envio, `msg_…`. Use-o para `get`, `cancel`, `reschedule` e `getTracking`.
statusEmailStatus
queued, scheduled, sending, sent, partial, cancelled ou failed. Leia este campo em vez de se basear no facto de a promise ter sido resolvida. `partial` é um estado próprio: alguns destinatários já a têm e não é possível anular o envio, pelo que tentar de novo é errado e reportar falha é falso.
mode'live' | 'test'
Que tipo de chave o enviou. Um envio de teste é registado e nunca transmitido.
fromstring
O endereço efetivamente autorizado e colocado na linha, que nem sempre é o que foi pedido.
subjectstring | null
Tal como foi enviado.
messageIdstring | null
O Message-ID RFC 5322. Null até o MIME existir. O serviço de envio reescreve o cabeçalho à saída, por isso nenhuma devolução nem relatório de entrega transporta este valor. É em `id` que um evento regressa.
threadIdstring | null
A thread em que ficou.
transportstring | null
Como a mensagem saiu. Null até ao despacho.
attemptsnumber
Quantas vezes o despacho foi tentado.
lastErrorstring | null
Porque falhou a última tentativa, literalmente.
scheduledAtstring | null
Instante ISO em que deve sair.
cancellableUntilstring | null
Enquanto o momento atual for anterior a este, cancel continua a funcionar.
sentAtstring | null
Instante ISO em que saiu.
tagsRecord<string, string>
O que enviou, devolvido tal e qual.
sourceEmailSource
composer, api, mcp, ai ou queue: que superfície o pediu. `api` é este cliente.
createdAtstring
Instante ISO em que o registo foi escrito.
replayedboolean
True quando uma Idempotency-Key correspondeu a um envio que já existia. Nada de novo foi enviado, e esta é a mensagem original.
translationEmailTranslationResource | undefined
Presente apenas numa mensagem que foi traduzida, e apenas onde todo o pedido guardado é transportado: esta resposta e `get`. `{ language, languageName, detectedSourceLanguage, subject, includeOriginal }`, todos códigos em vez de linhas de idioma. Uma linha de listagem nunca o tem, por isso a sua ausência aí não diz nada num sentido nem no outro.

Na língua do destinatário

translate escreve a mensagem na língua de outra pessoa antes de ela partir. O corpo, e o assunto a menos que o desative, é traduzido quando a API aceita o pedido, e o que saiu é o que vai sair: uma tradução que não pôde ser produzida recusa o envio em vez de o publicar na língua em que o escreveu.

translate.ts
const email = await openemail.emails.send({  from: '[email protected]',  to: '[email protected]',  subject: 'Your September invoice',  html: '<p>Invoice attached. Payment is due on the 14th.</p>',  translate: { to: 'de' },}) console.log(email.translation)// { language: 'de', languageName: 'German', detectedSourceLanguage: 'en', subject: true, includeOriginal: true }

Ninguém leu aquilo antes de partir. emails.translate é a mesma ida e volta parada um passo antes. Mostre-a a uma pessoa, deixe-a alterá-la e depois envie o que ela aprovou sem qualquer translate na chamada. Passá-lo outra vez traduziria uma segunda vez e deitaria fora as edições dela.

preview-translation.ts
const preview = await openemail.emails.translate({  subject: 'Your September invoice',  html: '<p>Invoice attached. Payment is due on the 14th.</p>',  to: 'de',}) console.log(preview.language.native, preview.detectedSourceLanguage) const approved = await showToSomebody(preview) await openemail.emails.send({  from: '[email protected]',  to: '[email protected]',  subject: approved.subject,  html: approved.html,})
render-picker.ts
import { LANGUAGES, isRtlLanguage, languageByCode, openemail, resolveLanguage } from '@openemail/sdk' LANGUAGES.length // 200 const current = await openemail.languages.list() resolveLanguage('Deutsch')?.code // 'de'resolveLanguage('zh-TW')?.code // 'zh-Hant'languageByCode('DE')?.native // 'Deutsch'isRtlLanguage('ar') // true

A tabela vem incluída, pela ordem do seletor, para que um seletor possa ser preenchido antes do primeiro pedido. languages.list() resolve para as mesmas linhas vindas da rede sob a forma de um array simples, para quem prefira as atuais às que esta versão trouxe. resolveLanguage aceita um código, um nome em inglês, um endónimo ou um alias (zh-TW é um alias de um código que já não é listado), languageByCode faz corresponder um código exato sem distinguir maiúsculas de minúsculas, e dezasseis das linhas são da direita para a esquerda. Pesquise native, label e code em conjunto, mostre native primeiro e guarde o código.

emails.translate não é repetido automaticamente. Gasta chamadas ao modelo e não escreve nada, por isso não há nada para tornar idempotente e uma repetição após um pedido sem resposta só compraria a mesma resposta duas vezes.

  • Um idioma que não resolve para nada é um validation_error em translate.to, antes de seja o que for ser enviado.
  • translation_too_long acima de 30 000 caracteres, translation_not_configured quando a instalação não tem IA configurada, translation_failed quando o fornecedor não respondeu. Nenhum deles envia a mensagem por traduzir como alternativa.
  • Funciona com template: é o resultado RENDERIZADO que é traduzido, por isso um corpo guardado serve todas as línguas em que os seus clientes leem. Um template que renderiza um documento inteiro mantém o seu doctype, os seus blocos <style> e as suas regras @font-face: só o corpo vai para o modelo e o resto é reposto à volta dele. O seu <title> fica intacto, e nada o mostra de qualquer forma.
  • Uma repetição não custa nada a mais. A tradução não faz parte da impressão digital de idempotência (o pedido faz, translate incluído), por isso repetir um envio sem resposta com a mesma Idempotency-Key reproduz a mensagem que já existe em vez de traduzir e enviar uma segunda.
  • Uma mensagem traduzida que esteja em fila ou agendada fica congelada contra alterações de texto. emails.reschedule continua a movê-la; mudar o que diz significa cancelar e enviar de novo.

Anexos

content vai em base64 na rede. Passe bytes e são codificados por si.

attachment.ts
attachments: [  { filename: 'invoice.pdf', content: pdfBytes, contentType: 'application/pdf' },]

toBase64 é exportado se precisar dele noutro sítio. Divide em blocos, o que btoa(String.fromCharCode(...bytes)) não faz. Esse falha em qualquer coisa acima de cerca de 100 kB, e falha no ficheiro real e não naquele com que testou.