ドキュメント本文へスキップ
Ruby

メールを送信する

`emails.send`: 1 通のメッセージを、今またはあとで送ります。

emails.send

send_email.rb
email = client.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: Pathname("invoice.pdf")}],  threadId: "CAHk7pQ2x9LmZ4-mail.example.com",  scheduledAt: "PT1H",  tags: {order: "4021"},  tracking: {opens: true, clicks: true}) puts email[:id], email[:status]

to、cc、bcc は受信者 1 人、または受信者の Array を受け取り、1 人だけの場合は自動的に Array に包まれます。それぞれ素のアドレス、Name <addr@host>、または email と name を持つ Hash のいずれかです。

メッセージはキーワード引数か、1 つの Hash として渡します。Hash と並べて渡したキーワード引数はその Hash にマージされ、同じフィールドを指定した場合はキーワード引数が優先されるため、client.emails.send(message, subject: "Re: your invoice") は前に作ったメッセージのフィールドを 1 つだけ変更します。キーは API の名前をそのまま使うので、replyTo と scheduledAt は camelCase のままです。一方 idempotency_key: と api_key: は呼び出しのオプションで、メッセージの一部にはなりません。

パラメーター

fromString or Hash必須
送信者。素のアドレス、`Name <addr@host>`、または `email` と `name` を持つ Hash です。このキーで送信できるアドレスでなければならず、そうでなければ呼び出しは 403 `from_address_forbidden` を送出します。代わりの送信者はないため、送信では常に送信元のアドレスを指定します。
toString, Hash or Array必須
受信者 1 人、または受信者の Array で、1 人だけの場合は自動的に包まれます。`to`、`cc`、`bcc` を合わせて最大 50 人で、それを超えると 422 `too_many_recipients` になります。
ccString, Hash or Array
50 人の受信者上限に数えられます。
bccString, Hash or Array
受信者ごとに 1 つのエンベロープが送信されるため、他の誰かが受け取るバイト列にこのアドレスが現れることはありません。これも 50 人に数えられます。
replyToString or Hash
単一のアドレスで、Reply-To ヘッダーとして送られます。
subjectString
最大 998 文字で、RFC 5322 の行の上限です。既定値は空で、空の件名はテンプレートまたは下書きの件名にフォールバックします。
htmlString
`html`、`text`、`draftId`、`template` のいずれか 1 つが必要です。`html` と `text` の両方が与えられたとき、受信者が見るのは HTML です。最大 1,000,000 文字。
textString
プレーンテキストの部分。最大 1,000,000 文字。
templateHash
保存済みのテンプレートをサーバー側でレンダリングします。`id`(id または slug を受け付けます)と、省略可能な `version`(Integer)、`props`、`slots` を持つ Hash です。`version` はリビジョンを固定します。省略すると、リクエストが受け付けられた時点で公開されているものが使われます。不明な prop や欠けている prop は、メッセージ内の空欄ではなく 422 になります。
draftIdString
保存済みの下書きを、書かれたとおりにこのエンベロープで送信します。`template` や `translate` とは組み合わせられません。
headersHash
ヘッダー名から String 値への対応で、`X-*`、`List-*`、Reply-To、Precedence、Auto-Submitted、Importance、Priority、Feedback-ID に限られます。トランスポートが自分で設定するものは、黙って捨てられるのではなく 422 `reserved_header` で拒否されます。
attachmentsArray<Hash>
それぞれ `filename`、`content`、省略可能な `contentType` を持つ Hash、または `fileId` だけを持つ Hash で、後者は `files.upload` で追加したものなど、すでにワークスペースにあるファイルを指します。`content` にバイト列を渡すと、自動的に base64 エンコードされます。ファイルは 20 個までで、インラインファイルはデコード後の合計で 5 MB が上限です。保存済みのファイルはそれより大きくてもよく、ダウンロードリンクとして送られます。
attachmentDeliveryString
`mime`、`link`、`auto` のいずれか。`auto` は、files ドメインが有効なドメインでファイルが 2 MB を超えるとダウンロードリンクとして送り、それ以外はメッセージ内に入れます。省略するとメールボックスの設定が適用され、その既定は `auto` です。
threadIdString
既存のスレッドへ返信します。トランスポートが In-Reply-To と References を書き込みます。
scheduledAtTime, DateTime or String
UTC の ISO 8601 時刻として送られる Time または DateTime、String の ISO 8601 時刻、または `PT1H` のような期間。1 年先まで指定でき、過去は指定できません。`cancellableForSeconds` とは組み合わせられません。Ruby の Date は日付だけの値として送られ、API はそれをその日の UTC 午前 0 時として読むため、時刻が重要なときは Time を渡してください。
cancellableForSecondsInteger
0 から 900。即時送信における取り消し猶予で、コンポーザーの取り消し機構をハードコードせずに公開したものです。
tagsHash
最大 10 個のラベル。キーは英字、数字、`_`、`-` からなる 1〜64 文字、値は最大 256 文字の String です。読み取りのたびにそのまま返され、解釈されることはありません。
signatureBoolean
このメッセージに、送信元アドレスの署名を付けるかどうか。そのアドレス自身の署名、catch-all が受け取ったアドレスならその catch-all の署名、それもなければ OpenEmail のフッターが付きます(そのアドレスでフッターを無効にしていない場合)。省略すると、`html` のボディは書かれたとおり署名なしで送られ、`text` だけのボディには付きます。領収書、パスワードリセット、ダイジェストなど、プログラムが誰かに代わって送るメールには `false` を設定してください。どれも個人の署名を付けるべきものではありません。テンプレート送信と暗号化送信には決して付きません。
trackingHash
省略可能な Boolean の `opens` と `clicks` を持つ Hash で、このメッセージに開封ピクセルを追加しリンクを書き換えるかどうかを指定します。送信元アドレス(またはそれを受け取った catch-all)でトラッキングが有効になっていない限りオフで、ここで指定したキーは、アドレスの設定がどうであれ、このメッセージについての扱いを決めます。
translateHash
受信者の言語で送信します。`to` と、省略可能な `from`、`subject`、`includeOriginal` を持つ Hash です。`to` はコード、英語名、またはその言語自身での名前を受け付け、`subject` と `includeOriginal` はどちらも既定で true です。リクエストが受け付けられた時点で確定するため、スケジュールされたメッセージは承認された文面で送られます。`draftId` と一緒に指定すると拒否されます。
idempotency_keyString
この送信のための独自のキーで、英字、数字、`_`、`.`、`:`、`-` からなる 1〜255 文字。指定しない場合、クライアントは呼び出しごとにキーを生成するため、自身のリトライで二重送信することはありません。指定すると、別のプロセスで再実行された送信は繰り返されずに再生されます。
api_keyString
複数のワークスペースに代わって送信するプロセスのために、クライアントのキーではなくこのキーで送信します。

レスポンス

Symbol キーの Hash なので、email[:status] でステータスを読めます。

idString
送信 id で、`msg_` の後に 16 進数 24 文字が続きます。`get`、`cancel`、`reschedule`、`get_tracking` に使います。
statusString
queued、scheduled、sending、sent、partial、bounced、cancelled、failed のいずれか。呼び出しが戻ったという事実ではなく、これを読んでください。即時送信はリクエスト内で配送され、通常は `sent`、`partial`、`failed` で返り、保留された送信は `queued` または `scheduled` で返ります。`partial` はそれ自体が 1 つの状態です。一部の受信者にはすでに届いていて取り消せないため、リトライは誤りで、失敗と報告するのは事実に反します。
modeString
`live` または `test`:どちらの種類のキーで送信したか。テスト送信は記録されますが、実際には送信されません。`transport` が `test` で、ステータスは `sent` になるため、受信箱ではなくレスポンスに対してアサーションしてください。
fromString
実際に認可され通信に載ったアドレスで、求められたものとは限りません。
subjectString or nil
送られたとおりです。
messageIdString or nil
RFC 5322 の Message-ID。MIME ができるまでは nil です。送信サービスは送り出すときにこのヘッダーを書き換えるため、バウンスや配信レポートにこの値が含まれることはありません。イベントが返ってくるときの手がかりは `id` です。
threadIdString or nil
着地したスレッドです。
transportString or nil
メッセージがどの経路で送られたか。配送されるまでは nil。
attemptsInteger
送出が何回試みられたか。
lastErrorString or nil
直近の試行が失敗した理由を、そのまま記したものです。
scheduledAtString or nil
送信予定の ISO 8601 時刻。
cancellableUntilString or nil
現在時刻がこれより前である間は、`cancel` がまだ有効です。
sentAtString or nil
送信された ISO 8601 時刻。
tagsHash
送ったものが、そのまま返ります。
sourceString
composer、api、mcp、ai、queue のいずれか。どの面が要求したかを示します。このクライアントは `api` です。
createdAtString
レコードが書き込まれた ISO 8601 時刻。
replayedBoolean
Idempotency-Key が既存の送信と一致したときに true。新たには何も送信されておらず、これは元のメッセージの現在の状態です。
translationHash
翻訳されたメッセージにだけ存在し、保存されたリクエスト全体を含む場所、つまりこのレスポンスと `get` にだけ現れます。`language`、`languageName`、`detectedSourceLanguage`、`subject`、`includeOriginal` を持ち、言語の行全体ではなくコードで表します。一覧の行には決して含まれないため、そこに無いことは何も意味しません。

受信者の言語で送る

translate は、メッセージが出ていく前にそれを別の人の言語で書き直します。本文と、無効にしない限り件名が、API がリクエストを受け付けた時点で翻訳され、その出力がそのまま送られます。翻訳を生成できなかった場合は、あなたが書いた言語のまま投函するのではなく送信を拒否します。

translate.rb
email = client.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"}) p email[:translation]

このとき email[:translation] は {language: "de", languageName: "German", detectedSourceLanguage: "en", subject: true, includeOriginal: true} になります。

それは送られる前に誰も読んでいません。emails.translate は同じ往復を 1 段階手前で止めたものです。結果を人に見せて修正してもらい、承認されたものを、呼び出しに translate を一切付けずに送信してください。もう一度渡すと 2 回目の翻訳が行われ、修正が捨てられてしまいます。

preview_translation.rb
preview = client.emails.translate(  subject: "Your September invoice",  html: "<p>Invoice attached. Payment is due on the 14th.</p>",  to: "de") puts preview.dig(:language, :native), preview[:subject], preview[:html]print "Send it as it is? [y/N] " if $stdin.gets.to_s.strip.casecmp?("y")  client.emails.send(    from: "[email protected]",    to: "[email protected]",    subject: preview[:subject],    html: preview[:html]  )end
languages.rb
p OpenEmail::LANGUAGES.size current = client.languages.listp current.size p OpenEmail.resolve_language("Deutsch")&.fetch(:code)p OpenEmail.resolve_language("zh-TW")&.fetch(:code)p OpenEmail.language_by_code("DE")&.fetch(:native)p OpenEmail.rtl_language?("ar")

これらの行は、このバージョンに同梱されている行数の 200、API が現在持つ行数、続いて "de"、"zh-Hant"、"Deutsch"、true を出力します。この表は OpenEmail::LANGUAGES として、ピッカーの表示順で同梱されています。code、label、native、flag、rtl を持つ Hash の凍結された Array なので、最初のリクエストの前にピッカーを埋められます。languages.list は同じ行を通信で取得し、素の Array として返します。このバージョンに同梱された行ではなく現在の行を使いたい呼び出し元向けです。OpenEmail.resolve_language はコード、英語名、その言語自身での名前、または別名(zh-TW はもう一覧にないコードの別名です)を受け取り、一致するものがなければ nil を返します。OpenEmail.language_by_code は大文字小文字を問わずコードの完全一致で照合し、16 の行は右から左に書く言語です。native、label、code をまとめて検索し、native を先に表示し、コードを保存してください。

emails.translate は自動的に再試行されません。モデル呼び出しを消費し、何も書き込まないので、冪等にすべきものがなく、応答のなかったリクエストの再試行は同じ答えを 2 度買うだけです。

  • API が照合できない言語は、何かが送信される前に translate.to に対する validation_error になります。
  • 30,000 文字を超えると translation_too_long、インストールに AI が設定されていなければ translation_not_configured、ワークスペースが当日の AI 操作を使い切っていれば 429 ai_quota_exceeded(UTC の午前 0 時にリセットされ、リトライはされません)、プロバイダーが応答しなければ translation_failed になります。いずれの場合も、代わりに未翻訳のメッセージが送られることはありません。
  • template と併用できます。翻訳されるのはレンダリング後の出力なので、保存された 1 つの本文が、顧客が読むすべての言語に対応できます。文書全体をレンダリングするテンプレートは、doctype、<style> ブロック、@font-face 規則を保ちます。モデルへ渡されるのは body だけで、残りは後から周りに戻されます。<title> はそのままで、どのみち何も表示しません。
  • 再試行に追加費用はかかりません。翻訳は冪等性のフィンガープリントの一部ではなく(リクエストは translate を含めて一部です)、応答のなかった送信を同じ Idempotency-Key で再試行すると、翻訳して 2 通目を送るのではなく、すでに存在するメッセージを再生します。
  • queued または scheduled の翻訳済みメッセージは、承認された文面を保持します。emails.reschedule で時刻を動かすことはできますが、emails.update は新しい文面を 409 translation_locked で拒否するため、内容を変えるにはキャンセルして送り直すことになります。

添付ファイル

content は通信上では base64 です。バイト列を渡せば自動的にエンコードされます。File.binread が返すようなバイナリの String、開いた File のような IO、または読み込みを任せられる Pathname を渡せます。

attachments.rb
attachments = [  {filename: "invoice.pdf", content: File.binread("invoice.pdf"), contentType: "application/pdf"},  {filename: "report.pdf", content: Pathname("report.pdf")},  {fileId: "file_6bb640f5b99e47deb758f1f5"}] client.emails.send(  from: "[email protected]",  to: "[email protected]",  subject: "Your documents",  text: "Both are attached.",  attachments:)

File.read が返すようなテキストとしてタグ付けされた String は、すでに base64 であるとみなされ、base64 でなければ何かが送信される前に ArgumentError を送出します。ファイルは File.binread で読むか、テキストとしてタグ付けされて届いたバイト列には .b を呼んでください。

同じエンコードが他の場所で必要なら OpenEmail.to_base64 があります。バイナリの String、IO、Pathname を受け取り、改行のない厳密な base64 を返します。