Zur Dokumentation springen
SDK

Eine E-Mail senden

`emails.send`: eine Nachricht, jetzt oder später.

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 und bcc nehmen einen oder mehrere Empfänger entgegen, und ein einzelner wird für Sie verpackt. Jeder darf eine blanke Adresse, Name <addr@host> oder { email, name } sein.

Parameter

fromRecipientInputerforderlich
Der Absender. Eine bloße Adresse, `Name <addr@host>` oder ein Objekt. Muss eine sein, als die dieser Schlüssel senden darf. Es gibt keinen Ersatzabsender, denn der Ersatz wäre die Standardadresse des Workspace, und die ändert sich, wenn Adressen kommen und gehen.
toRecipientInput | RecipientInput[]erforderlich
Ein oder mehrere Empfänger; ein einzelner wird für Sie verpackt. Höchstens 50 über to, cc und bcc zusammen.
ccRecipientInput | RecipientInput[]
Zählt gegen das Limit von 50 Empfängern.
bccRecipientInput | RecipientInput[]
Wird in den Bytes, die andere erhalten, nie genannt, denn pro Empfänger wird ein eigener Umschlag übertragen.
replyToRecipientInput
Eine einzelne Adresse, wird als Reply-To-Header gesendet.
subjectstring
Höchstens 998 Zeichen, das Zeilenlimit von RFC 5322. Standardmäßig leer.
htmlstring
Eines von html, text, draftId oder template ist erforderlich. HTML ist das, was Empfänger sehen, wenn sowohl html als auch text angegeben sind.
textstring
Der Nur-Text-Teil.
template{ id, version?, props?, slots? }
Rendert ein gespeichertes Template serverseitig. `version` schreibt eine Revision fest; lassen Sie es weg, um das zu verwenden, was bei Annahme der Anfrage veröffentlicht ist. Ein unbekanntes oder fehlendes prop ergibt ein 422 und keine Lücke in der Nachricht.
draftIdstring
Sendet einen gespeicherten Entwurf unter diesem Umschlag.
headersRecord<string, string>
`X-*`, `List-*`, Reply-To, Precedence, Auto-Submitted, Importance, Priority und Feedback-Id. Alles, was der Transport selbst setzt, wird abgelehnt statt stillschweigend verworfen.
attachmentsAttachmentInput[]
`{ filename, content, contentType? }` oder `{ fileId }`, das eine bereits im Workspace liegende Datei benennt. Übergeben Sie Bytes als content, dann werden sie für Sie base64-kodiert. 20 Dateien, wobei eingebettete Dateien nach dem Dekodieren zusammen auf 5 MB begrenzt sind. Eine gespeicherte Datei darf größer sein und reist als Download-Link.
attachmentDeliveryAttachmentDeliveryMode
`mime`, `link` oder `auto`. `auto` überträgt Dateien als Download-Links, sobald sie 2 MB überschreiten und die Domain eine aktive Dateien-Domain hat, und andernfalls innerhalb der Nachricht. Weggelassen gilt die Postfacheinstellung, die standardmäßig `auto` ist.
threadIdstring
Antwort in einen bestehenden Thread. Der Transport schreibt In-Reply-To und References.
scheduledAtDate | string
Ein Date, ein ISO-8601-Zeitpunkt oder eine Dauer wie `PT1H`. Bis zu ein Jahr voraus, nie in der Vergangenheit. Lässt sich nicht mit cancellableForSeconds kombinieren.
cancellableForSecondsnumber
0 bis 900. Ein Rückgängig-Fenster bei einem sofortigen Versand: der Rückgängig-Mechanismus des Composers, offengelegt statt fest verdrahtet.
tagsRecord<string, string>
Bis zu 10 Labels, werden zurückgegeben und sind filterbar. Werden nie interpretiert.
signatureboolean
Ob diese Nachricht die Signatur der Absenderadresse trägt, also die eigene Signatur dieser Adresse oder sonst die für Alle Adressen gesetzte. Standard ist true, denn eine Signatur gehört zur Adresse und nicht zu dem Client, der die Nachricht gesendet hat. Setzen Sie `false` für Mail, die ein Programm im Namen einer Person sendet, etwa eine Quittung, ein Passwort-Reset oder eine Zusammenfassung, unter denen niemand die Unterschrift einer Person erwartet.
tracking{ opens?, clicks? }
Ob für diese Nachricht ein Öffnungs-Pixel hinzugefügt und Links umgeschrieben werden. Aktiv, sofern der Workspace-Inhaber das Tracking nicht für die Absenderadresse oder für Alle Adressen abgeschaltet hat, und jedes hier angegebene Feld entscheidet diese eine Nachricht, unabhängig davon, wie die Adresse eingestellt ist.
translate{ to, from?, subject?, includeOriginal? }
Sendet sie in der Sprache des Empfängers. `to` nimmt einen Code, einen englischen Namen oder den Eigennamen der Sprache entgegen; `subject` und `includeOriginal` sind beide standardmäßig true. Wird bei Annahme der Anfrage aufgelöst, eine geplante Nachricht trägt daher genau die freigegebenen Worte. Wird zusammen mit `draftId` abgelehnt.

Antwort

idstring
Die Versand-id, `msg_…`. Verwenden Sie sie für `get`, `cancel`, `reschedule` und `getTracking`.
statusEmailStatus
queued, scheduled, sending, sent, partial, cancelled oder failed. Lesen Sie dies und nicht die Tatsache, dass das Promise aufgelöst hat. `partial` ist ein eigener Zustand: Einige Empfänger haben die Nachricht, und das lässt sich nicht rückgängig machen, ein erneuter Versuch ist daher falsch und einen Fehlschlag zu melden ist eine Lüge.
mode'live' | 'test'
Welche Art von Schlüssel sie gesendet hat. Ein Testversand wird erfasst und nie übertragen.
fromstring
Die tatsächlich autorisierte und auf die Leitung gegebene Adresse, die nicht immer die angeforderte ist.
subjectstring | null
Wie gesendet.
messageIdstring | null
Die Message-ID nach RFC 5322. Null, bis das MIME existiert. Der Versanddienst schreibt den Header auf dem Weg hinaus um, kein Bounce und kein Zustellbericht trägt daher diesen Wert. `id` ist das, worüber ein Ereignis zurückkommt.
threadIdstring | null
Der Thread, in dem sie gelandet ist.
transportstring | null
Wie die Nachricht hinausging. Null bis zum Versand.
attemptsnumber
Wie oft der Versand versucht wurde.
lastErrorstring | null
Warum der letzte Versuch fehlschlug, wörtlich.
scheduledAtstring | null
ISO-Zeitpunkt, zu dem sie hinausgehen soll.
cancellableUntilstring | null
Solange die aktuelle Zeit davor liegt, funktioniert cancel noch.
sentAtstring | null
ISO-Zeitpunkt, zu dem sie hinausging.
tagsRecord<string, string>
Was Sie gesendet haben, zurückgegeben.
sourceEmailSource
composer, api, mcp, ai oder queue: welche Oberfläche angefragt hat. `api` ist dieser Client.
createdAtstring
ISO-Zeitpunkt, zu dem der Datensatz geschrieben wurde.
replayedboolean
True, wenn ein Idempotency-Key auf einen bereits existierenden Versand passte. Es wurde nichts Neues gesendet, und dies ist die ursprüngliche Nachricht.
translationEmailTranslationResource | undefined
Nur bei einer übersetzten Nachricht vorhanden, und nur dort, wo die gesamte gespeicherte Anfrage mitgeführt wird: in dieser Antwort und bei `get`. `{ language, languageName, detectedSourceLanguage, subject, includeOriginal }`, durchweg Codes statt Sprachzeilen. Eine Listenzeile hat es nie, sein Fehlen dort sagt daher in keine Richtung etwas aus.

In der Sprache des Empfängers

translate verfasst die Nachricht vor dem Versand in der Sprache eines anderen. Der Body und, sofern Sie das nicht abschalten, der Betreff werden übersetzt, sobald die API die Anfrage annimmt, und was dabei herauskam, geht hinaus: Eine Übersetzung, die nicht erzeugt werden konnte, lässt den Versand scheitern, statt die Nachricht in der Sprache zu verschicken, in der Sie sie geschrieben haben.

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 }

Niemand hat das gelesen, bevor es hinausging. emails.translate ist derselbe Weg, einen Schritt früher angehalten. Zeigen Sie das Ergebnis einer Person, lassen Sie sie es ändern und senden Sie dann das Freigegebene ganz ohne translate am Aufruf. Es erneut zu übergeben würde ein zweites Mal übersetzen und ihre Änderungen verwerfen.

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

Die Tabelle ist mitgeliefert, in der Reihenfolge des Auswahlfelds, ein Auswahlfeld lässt sich daher schon vor der ersten Anfrage füllen. languages.list() löst als einfaches array zu denselben Zeilen von der Leitung auf, für Aufrufer, denen die aktuellen lieber sind als die, mit denen diese Version ausgeliefert wurde. resolveLanguage nimmt einen Code, einen englischen Namen, ein Endonym oder einen Alias entgegen (zh-TW ist ein Alias eines nicht mehr gelisteten Codes), languageByCode trifft einen exakten Code ohne Beachtung der Groß- und Kleinschreibung, und sechzehn der Zeilen laufen von rechts nach links. Durchsuchen Sie native, label und code gemeinsam, zeigen Sie native zuerst und speichern Sie den Code.

emails.translate wird nicht automatisch wiederholt. Es verbraucht Modellaufrufe und schreibt nichts, es gibt also nichts idempotent zu machen, und eine Wiederholung nach einer unbeantworteten Anfrage würde dieselbe Antwort nur zweimal bezahlen.

  • Eine Sprache, die auf nichts auflöst, ergibt einen validation_error auf translate.to, bevor irgendetwas gesendet wird.
  • translation_too_long bei über 30.000 Zeichen, translation_not_configured, wenn für die Installation keine KI konfiguriert ist, translation_failed, wenn der Anbieter nicht geantwortet hat. Keiner dieser Fälle sendet die Nachricht ersatzweise unübersetzt.
  • Funktioniert mit template: Übersetzt wird die GERENDERTE Ausgabe, ein gespeicherter Body bedient daher jede Sprache, in der Ihre Kunden lesen. Ein Template, das ein ganzes Dokument rendert, behält seinen doctype, seine <style>-Blöcke und seine @font-face-Regeln: Nur der Body geht an das Modell, der Rest wird wieder darum gelegt. Sein <title> bleibt unangetastet, was ohnehin nirgends angezeigt wird.
  • Eine Wiederholung kostet nichts zusätzlich. Die Übersetzung ist nicht Teil des Idempotenz-Fingerabdrucks (die Anfrage schon, translate eingeschlossen), eine Wiederholung eines unbeantworteten Versands mit demselben Idempotency-Key spielt daher die bereits existierende Nachricht erneut ab, statt ein zweites Mal zu übersetzen und zu senden.
  • Eine übersetzte Nachricht, die queued oder scheduled ist, ist gegen Änderungen am Wortlaut eingefroren. emails.reschedule verschiebt sie weiterhin; ihren Inhalt zu ändern bedeutet abbrechen und erneut senden.

Anhänge

content ist auf der Leitung base64. Übergeben Sie Bytes, dann werden sie für Sie kodiert.

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

toBase64 wird exportiert, falls Sie es anderswo brauchen. Es arbeitet in Blöcken, was btoa(String.fromCharCode(...bytes)) nicht tut. Letzteres scheitert an allem oberhalb von rund 100 kB, und zwar an der echten Datei statt an der, mit der Sie getestet haben.