Envia un correu
`emails.send`: un missatge, ara o més tard.
emails.send
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.
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.
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,})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') // trueLa 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_erroratranslate.to, abans d'enviar res. translation_too_longper sobre de 30.000 caràcters,translation_not_configuredquan la instal·lació no té cap IA configurada,translation_failedquan 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
translateinclòs), de manera que reintentar un enviament sense resposta amb la mateixaIdempotency-Keyreprodueix 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.rescheduleencara 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.
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.