Ves a la documentació
SDK

Envia un correu

`emails.send`: un missatge, ara o més tard.

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 i bcc accepten un destinatari o molts, i un de sol l'embolcallem per tu. Cadascun pot ser una adreça nua, Name <addr@host> o { email, name }.

Paràmetres

fromRecipientInputobligatori
El remitent. Una adreça nua, `Name <addr@host>` o un objecte. Ha de ser una amb què aquesta clau pugui enviar. No hi ha cap remitent de reserva, perquè la reserva seria l'adreça per defecte de l'espai de treball, que canvia a mesura que les adreces van i venen.
toRecipientInput | RecipientInput[]obligatori
Un destinatari o molts; un de sol l'embolcallem per tu. Com a màxim 50 entre to, cc i bcc sumats.
ccRecipientInput | RecipientInput[]
Compta per al límit de 50 destinataris.
bccRecipientInput | RecipientInput[]
No s'anomena mai en els bytes que rep ningú altre, perquè es transmet un sobre per destinatari.
replyToRecipientInput
Una sola adreça, que s'envia com a capçalera Reply-To.
subjectstring
Com a màxim 998 caràcters, el límit de línia de l'RFC 5322. Per defecte és buit.
htmlstring
Cal un d'aquests: html, text, draftId o template. Els destinataris veuen l'HTML quan s'indiquen tant html com text.
textstring
La part de text pla.
template{ id, version?, props?, slots? }
Renderitza una plantilla desada al servidor. `version` la fixa; omet-lo per fer servir el que estigui publicat quan s'accepti la sol·licitud. Una prop desconeguda o absent és un 422 i no pas un buit dins del missatge.
draftIdstring
Envia un esborrany desat amb aquest sobre.
headersRecord<string, string>
`X-*`, `List-*`, Reply-To, Precedence, Auto-Submitted, Importance, Priority i Feedback-Id. Tot allò que el transport defineix ell mateix es rebutja en comptes de descartar-se en silenci.
attachmentsAttachmentInput[]
`{ filename, content, contentType? }`, o `{ fileId }` anomenant un fitxer que ja és a l'espai de treball. Passa bytes a content i te'ls codifiquem en base64. 20 fitxers, amb els fitxers inline limitats a 5 MB en total un cop descodificats. Un fitxer desat pot ser més gran i viatja com a enllaç de descàrrega.
attachmentDeliveryAttachmentDeliveryMode
`mime`, `link` o `auto`. `auto` porta els fitxers com a enllaços de descàrrega quan superen els 2 MB en un domini amb un domini de fitxers actiu, i dins del missatge en cas contrari. Si s'omet, s'aplica la configuració de la bústia, que per defecte és `auto`.
threadIdstring
Respon dins d'una conversa existent. El transport escriu In-Reply-To i References.
scheduledAtDate | string
Un Date, un instant ISO-8601 o una durada com ara `PT1H`. Fins a un any endavant, mai en el passat. No es pot combinar amb cancellableForSeconds.
cancellableForSecondsnumber
De 0 a 900. Una finestra per desfer en un enviament immediat: el mecanisme de desfer del redactor, exposat en comptes de codificat de manera fixa.
tagsRecord<string, string>
Fins a 10 etiquetes, retornades i filtrables. No s'interpreten mai.
signatureboolean
Si aquest missatge porta la signatura de l'adreça des de la qual s'envia, que és la signatura pròpia d'aquella adreça o si no la definida per a Totes les adreces. Per defecte és cert, perquè una signatura pertany a l'adreça i no pas al client que hagi enviat el missatge. Posa-ho a `false` per al correu que un programa envia en nom d'algú, com ara un rebut, un restabliment de contrasenya o un resum, que no volen cap comiat personal a sota.
tracking{ opens?, clicks? }
Si cal afegir un píxel d'obertura i reescriure els enllaços d'aquest missatge. Activat tret que el propietari de l'espai de treball hagi desactivat el seguiment per a l'adreça des de la qual s'envia o per a Totes les adreces, i qualsevol dels dos camps indicats aquí resol aquell missatge concret, sigui com sigui la configuració de l'adreça.
translate{ to, from?, subject?, includeOriginal? }
Envia'l en l'idioma del destinatari. `to` accepta un codi, un nom en anglès o el nom propi de l'idioma; `subject` i `includeOriginal` són certs per defecte tots dos. Es resol quan s'accepta la sol·licitud, de manera que un missatge programat porta les paraules que es van aprovar. Es rebutja al costat de `draftId`.

Resposta

idstring
L'id de l'enviament, `msg_…`. Fes-lo servir per a `get`, `cancel`, `reschedule` i `getTracking`.
statusEmailStatus
queued, scheduled, sending, sent, partial, cancelled o failed. Llegeix això i no pas el fet que la promesa s'hagi resolt. `partial` és un estat propi: alguns destinataris ja el tenen i no se'ls pot desenviar, de manera que reintentar és un error i informar d'una fallada és mentida.
mode'live' | 'test'
Quina mena de clau el va enviar. Un enviament de prova es registra i no es transmet mai.
fromstring
L'adreça realment autoritzada i posada al cable, que no sempre és la que s'ha demanat.
subjectstring | null
Tal com s'ha enviat.
messageIdstring | null
El Message-ID de l'RFC 5322. Null fins que existeix el MIME. El servei d'enviament reescriu la capçalera a la sortida, de manera que cap rebot ni informe de lliurament no porta aquest valor. `id` és allò amb què torna un esdeveniment.
threadIdstring | null
La conversa on ha anat a parar.
transportstring | null
Com ha sortit el missatge. Null fins a la tramesa.
attemptsnumber
Quantes vegades s'ha intentat la tramesa.
lastErrorstring | null
Per què ha fallat l'últim intent, literalment.
scheduledAtstring | null
Instant ISO en què ha de sortir.
cancellableUntilstring | null
Mentre l'ara sigui anterior a aquest instant, la cancel·lació encara funciona.
sentAtstring | null
Instant ISO en què va sortir.
tagsRecord<string, string>
El que has enviat, retornat tal qual.
sourceEmailSource
composer, api, mcp, ai o queue: quina superfície ho ha demanat. `api` és aquest client.
createdAtstring
Instant ISO en què es va escriure el registre.
replayedboolean
Cert quan una Idempotency-Key ha coincidit amb un enviament que ja existia. No s'ha enviat res de nou, i aquest és el missatge original.
translationEmailTranslationResource | undefined
Present només en un missatge que s'ha traduït, i només allà on es porta tota la sol·licitud desada: aquesta resposta i `get`. `{ language, languageName, detectedSourceLanguage, subject, includeOriginal }`, tot codis i no pas files d'idioma. Una fila de llista no el té mai, de manera que la seva absència allà no diu res en cap sentit.

En l'idioma del destinatari

translate escriu el missatge en l'idioma d'una altra persona abans que surti. El cos, i l'assumpte tret que ho desactivis, es tradueixen quan l'API accepta la sol·licitud, i el que n'ha sortit és el que s'envia: una traducció que no s'ha pogut produir fa rebutjar l'enviament en comptes d'enviar-lo en l'idioma en què l'has escrit.

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 }

Ningú no ho ha llegit abans que sortís. emails.translate és el mateix viatge d'anada i tornada aturat un pas abans. Ensenya-ho a una persona, deixa que ho canviï, i després envia el que ha aprovat sense cap translate a la crida. Tornar-lo a passar traduiria una segona vegada i llençaria les seves edicions.

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

La taula ve inclosa al paquet, en ordre de selector, de manera que un selector es pot omplir abans de la primera sol·licitud. languages.list() es resol en les mateixes files vingudes del cable com un array pla, per a qui prefereixi les actuals en comptes de les que van sortir amb aquesta versió. resolveLanguage accepta un codi, un nom en anglès, un endònim o un àlies (zh-TW és un àlies d'un codi que ja no és a la llista), languageByCode fa coincidir un codi exacte sense distingir majúscules, i setze de les files són de dreta a esquerra. Cerca alhora a native, label i code, mostra native primer i desa el codi.

emails.translate no es reintenta automàticament. Gasta crides al model i no escriu res, de manera que no hi ha res per fer idempotent i un reintent després d'una sol·licitud sense resposta només compraria la mateixa resposta dues vegades.

  • Un idioma que no es resol a res és un validation_error a translate.to, abans d'enviar res.
  • translation_too_long per sobre de 30.000 caràcters, translation_not_configured quan la instal·lació no té cap IA configurada, translation_failed quan el proveïdor no ha respost. Cap d'ells no envia el missatge sense traduir com a alternativa.
  • Funciona amb template: el que es tradueix és la sortida RENDERITZADA, de manera que un sol cos desat serveix per a tots els idiomes en què llegeixen els teus clients. Una plantilla que renderitza un document sencer conserva el doctype, els blocs <style> i les regles @font-face: només el cos va al model i la resta es torna a posar al seu voltant. El seu <title> es deixa tal com està, que de totes maneres no es mostra enlloc.
  • Un reintent no costa res de més. La traducció no forma part de l'empremta d'idempotència (la sol·licitud sí, amb translate inclòs), de manera que reintentar un enviament sense resposta amb la mateixa Idempotency-Key reprodueix el missatge que ja existeix en comptes de traduir-ne i enviar-ne un segon.
  • Un missatge traduït que està a la cua o programat queda congelat davant de canvis de redactat. emails.reschedule encara el mou; canviar el que diu vol dir cancel·lar-lo i tornar-lo a enviar.

Adjunts

content va en base64 pel cable. Passa-hi bytes i te'ls codifiquem.

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

toBase64 s'exporta per si el necessites en un altre lloc. Treballa per trossos, cosa que btoa(String.fromCharCode(...bytes)) no fa. Aquest últim falla amb qualsevol cosa que passi dels 100 kB, i falla amb el fitxer real i no pas amb el que has fet servir per provar.