Wyślij e-mail
`emails.send`: jedna wiadomość, teraz albo później.
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 przyjmują jednego odbiorcę albo wielu, a pojedynczy jest opakowywany za Ciebie. Każdy może być samym adresem, Name <addr@host> albo { email, name }.
Parametry
fromRecipientInputwymagane- Nadawca. Sam adres, `Name <addr@host>` albo obiekt. Musi to być adres, z którego ten klucz może wysyłać. Nie ma nadawcy zastępczego, bo zastępczym nadawcą byłby domyślny adres obszaru roboczego, który zmienia się, gdy adresy pojawiają się i znikają.
toRecipientInput | RecipientInput[]wymagane- Jeden odbiorca albo wielu; pojedynczy jest opakowywany za Ciebie. Najwyżej 50 łącznie w to, cc i bcc.
ccRecipientInput | RecipientInput[]- Liczy się do limitu 50 odbiorców.
bccRecipientInput | RecipientInput[]- Nigdy nienazywane w bajtach, które dostaje ktokolwiek inny, bo na każdego odbiorcę transmitowana jest osobna koperta.
replyToRecipientInput- Pojedynczy adres, wysyłany jako nagłówek Reply-To.
subjectstring- Najwyżej 998 znaków, czyli limit linii z RFC 5322. Domyślnie pusty.
htmlstring- Wymagane jest jedno z html, text, draftId albo template. HTML jest tym, co widzą odbiorcy, gdy podano i html, i text.
textstring- Część w czystym tekście.
template{ id, version?, props?, slots? }- Wyrenderuj zapisany szablon po stronie serwera. `version` przypina wersję; pomiń je, żeby użyć tej, która jest opublikowana w chwili przyjęcia żądania. Nieznana albo brakująca właściwość daje 422, a nie puste miejsce w wiadomości.
draftIdstring- Wyślij zapisaną wersję roboczą pod tą kopertą.
headersRecord<string, string>- `X-*`, `List-*`, Reply-To, Precedence, Auto-Submitted, Importance, Priority i Feedback-Id. Wszystko, co transport ustawia sam, jest odrzucane, a nie po cichu pomijane.
attachmentsAttachmentInput[]- `{ filename, content, contentType? }` albo `{ fileId }` nazywające plik już obecny w przestrzeni roboczej. Przekaż bajty jako content, a zostaną zakodowane w base64 za Ciebie. 20 plików, przy czym pliki inline łącznie do 5 MB po zdekodowaniu. Plik przechowywany może być większy i podróżuje jako link do pobrania.
attachmentDeliveryAttachmentDeliveryMode- `mime`, `link` albo `auto`. `auto` niesie pliki jako linki do pobrania, gdy przekroczą 2 MB w domenie z aktywną domeną plików, a w przeciwnym razie wewnątrz wiadomości. Pominięte — obowiązuje ustawienie skrzynki, a ono domyślnie ma `auto`.
threadIdstring- Odpowiedź w istniejącym wątku. Transport zapisuje In-Reply-To i References.
scheduledAtDate | string- Date, instant ISO-8601 albo czas trwania w rodzaju `PT1H`. Do roku naprzód, nigdy w przeszłość. Nie można łączyć z cancellableForSeconds.
cancellableForSecondsnumber- Od 0 do 900. Okno cofnięcia przy wysyłce natychmiastowej: mechanizm cofania z kompozytora, wystawiony zamiast zaszyty na sztywno.
tagsRecord<string, string>- Do 10 etykiet, odsyłanych z powrotem i filtrowalnych. Nigdy nieinterpretowane.
signatureboolean- Czy ta wiadomość niesie podpis adresu, z którego jest wysyłana, czyli własny podpis tego adresu albo ten ustawiony dla Wszystkich adresów. Domyślnie true, bo podpis należy do adresu, a nie do tego, który klient wysłał wiadomość. Ustaw `false` dla poczty, którą program wysyła w czyimś imieniu, na przykład potwierdzenia, resetu hasła albo zestawienia — żadne z nich nie chce mieć pod sobą podpisu człowieka.
tracking{ opens?, clicks? }- Czy dodać piksel otwarcia i przepisać linki dla tej wiadomości. Włączone, chyba że właściciel przestrzeni roboczej wyłączył śledzenie dla adresu, z którego wiadomość jest wysyłana, albo dla Wszystkich adresów; każde z tych pól podane tutaj rozstrzyga tę jedną wiadomość niezależnie od ustawienia adresu.
translate{ to, from?, subject?, includeOriginal? }- Wyślij ją w języku odbiorcy. `to` przyjmuje kod, angielską nazwę albo własną nazwę języka; `subject` i `includeOriginal` domyślnie są true. Rozwiązywane, gdy żądanie zostaje przyjęte, więc zaplanowana wiadomość niesie słowa, które zatwierdzono. Odrzucane obok `draftId`.
Odpowiedź
idstring- Identyfikator wysyłki, `msg_…`. Używaj go w `get`, `cancel`, `reschedule` i `getTracking`.
statusEmailStatus- queued, scheduled, sending, sent, partial, cancelled albo failed. Czytaj to, a nie fakt, że obietnica się rozwiązała. `partial` to osobny stan: część odbiorców ma wiadomość i nie da się jej cofnąć, więc ponawianie jest błędem, a raportowanie porażki kłamstwem.
mode'live' | 'test'- Jakiego rodzaju klucz ją wysłał. Wysyłka testowa jest zapisywana i nigdy nie jest transmitowana.
fromstring- Adres faktycznie autoryzowany i umieszczony na łączu, nie zawsze ten, o który proszono.
subjectstring | null- Tak jak wysłano.
messageIdstring | null- Message-ID z RFC 5322. Null, dopóki nie powstanie MIME. Usługa wysyłkowa przepisuje ten nagłówek na wyjściu, więc żaden bounce ani raport doręczenia nie niesie tej wartości. `id` jest tym, na czym wraca zdarzenie.
threadIdstring | null- Wątek, w którym wylądowała.
transportstring | null- Jak wiadomość wyszła. Null do czasu wysłania.
attemptsnumber- Ile razy próbowano wysłać.
lastErrorstring | null- Dlaczego ostatnia próba się nie powiodła, dosłownie.
scheduledAtstring | null- Instant ISO, w którym ma wyjść.
cancellableUntilstring | null- Dopóki teraz jest przed tą chwilą, anulowanie działa.
sentAtstring | null- Instant ISO, w którym wyszła.
tagsRecord<string, string>- To, co wysłałeś, odesłane z powrotem.
sourceEmailSource- composer, api, mcp, ai albo queue: która powierzchnia poprosiła. `api` to ten klient.
createdAtstring- Instant ISO, w którym zapisano rekord.
replayedboolean- True, gdy `Idempotency-Key` pasował do wysyłki, która już istniała. Nic nowego nie wysłano, a to jest oryginalna wiadomość.
translationEmailTranslationResource | undefined- Obecne tylko na wiadomości, która została przetłumaczona, i tylko tam, gdzie niesione jest całe zapisane żądanie: w tej odpowiedzi i w `get`. `{ language, languageName, detectedSourceLanguage, subject, includeOriginal }`, same kody, a nie wiersze języków. Wiersz listy nigdy tego nie ma, więc brak w nim nie mówi nic w żadną stronę.
W języku odbiorcy
translate zapisuje wiadomość w czyimś innym języku, zanim ona wyjdzie. Treść, a jeśli tego nie wyłączysz, to i temat, są tłumaczone w chwili przyjęcia żądania przez API, a to, co z tego wyszło, jest tym, co idzie dalej: tłumaczenie, którego nie udało się wytworzyć, odrzuca wysyłkę, zamiast nadawać ją w języku, w którym ją napisałeś.
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 }Nikt tego nie przeczytał, zanim wyszło. emails.translate to ta sama podróż, zatrzymana krok wcześniej. Pokaż to człowiekowi, pozwól mu zmienić, a potem wyślij to, co zatwierdził, w ogóle bez translate w wywołaniu. Ponowne przekazanie przetłumaczyłoby tekst drugi raz i wyrzuciło jego poprawki.
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') // trueTabela jest dołączona do paczki, w kolejności do wyboru, więc listę wyboru można wypełnić jeszcze przed pierwszym żądaniem. languages.list() rozwiązuje się tymi samymi wierszami z łącza, jako zwykła tablica, dla kogoś, kto woli te bieżące niż te, z którymi wyszła ta wersja. resolveLanguage przyjmuje kod, nazwę angielską, endonim albo alias (zh-TW jest aliasem kodu, którego już nie ma na liście), languageByCode dopasowuje dokładny kod bez względu na wielkość liter, a szesnaście wierszy zapisuje się od prawej do lewej. Przeszukuj native, label i code razem, pokazuj najpierw native i zapisuj kod.
emails.translate nie jest ponawiane automatycznie. Kosztuje wywołania modelu i niczego nie zapisuje, więc nie ma czego czynić idempotentnym, a ponowienie po nieodebranej odpowiedzi kupiłoby tylko tę samą odpowiedź dwa razy.
- Język, który nie rozwiązuje się do niczego, to
validation_errornatranslate.to, zanim cokolwiek wyjdzie. translation_too_longpowyżej 30 000 znaków,translation_not_configured, gdy instalacja nie ma skonfigurowanego AI,translation_failed, gdy dostawca nie odpowiedział. Żaden z nich nie wysyła wiadomości nieprzetłumaczonej w ramach zapasowego rozwiązania.- Działa z
template: tłumaczone jest WYRENDEROWANE wyjście, więc jedna zapisana treść obsługuje każdy język, w którym czytają Twoi klienci. Szablon renderujący cały dokument zachowuje swój doctype, bloki<style>i reguły@font-face: do modelu idzie tylko treść, a reszta jest z powrotem wokół niej odtwarzana. Jego<title>pozostaje nietknięty i tak niczego nie wyświetla. - Ponowienie nie kosztuje nic dodatkowo. Tłumaczenie nie jest częścią odcisku idempotencji (żądanie jest, wraz z
translate), więc ponowienie nieodebranej wysyłki z tym samymIdempotency-Keyodtwarza wiadomość, która już istnieje, zamiast tłumaczyć i wysyłać drugą. - Przetłumaczona wiadomość, która jest w kolejce albo zaplanowana, jest zamrożona na zmiany treści.
emails.reschedulenadal ją przesuwa; zmiana tego, co mówi, oznacza anulowanie i wysłanie od nowa.
Załączniki
content jest na łączu w base64. Przekaż bajty, a zostaną zakodowane za Ciebie.
attachments: [ { filename: 'invoice.pdf', content: pdfBytes, contentType: 'application/pdf' },]toBase64 jest eksportowane, gdybyś potrzebował go gdzie indziej. Dzieli dane na kawałki, czego btoa(String.fromCharCode(...bytes)) nie robi. Tamto wywraca się na wszystkim powyżej mniej więcej 100 kB i wywraca się na prawdziwym pliku, a nie na tym, na którym testowałeś.