Ir a la documentación
C#

client.Emails

Cada método de este espacio de nombres: su firma, sus parámetros, lo que devuelve y un ejemplo.

Métodos

Send mail now or later, in batches or translated, change or cancel it before it goes, and follow what happened to it, recipient by recipient and event by event. It also scores a message before it is sent and writes, rewrites or titles one with AI.

Emails.SendAsync

Send, schedule or translate and send one email

Alcancesemails:send
Firma
Task<JsonObject> SendAsync(    IReadOnlyDictionary<string, object?> body,    string? idempotencyKey = null,    string? apiKey = null,    CancellationToken cancellationToken = default)

Sends one message now, or holds it for later with scheduledAt or an undo window with cancellableForSeconds. The body comes from exactly one source: html and or text, a stored template, or an existing draftId. Naming none is a 422, and template alongside html, text or draftId is refused. An immediate send is dispatched inside the request, so the call usually returns a sent, partial or failed message. A held send comes back as queued or scheduled, so read status rather than treating a returned message as delivered mail.

Every call carries an Idempotency-Key. The SDK generates one per call and reuses it on that call's retries, and the API claims it against the key's own unique index before anything is dispatched, so a retried network failure replays the original message instead of sending a second one. Pass idempotencyKey: to extend that across processes and restarts, deriving it from what made the send necessary rather than from a clock. A replay returns replayed set to true and the stored message in its current state. The same key with a different body is a 422 idempotency_key_reuse.

Add translate to deliver the message in the recipient's language. The translation runs when the request is accepted, before any record exists, so a scheduled send carries the approved wording and a translation that cannot be produced refuses the whole send: nothing is ever delivered untranslated as a fallback. By default the subject is translated too and your original text is placed below the translation, captioned in the target language. It works with template, translating what the template rendered, and is refused alongside draftId because a draft goes as it was written.

Parámetros

fromstring or dictionaryObligatorio

Sender as [email protected], Acme Billing <[email protected]> or a dictionary with email and name. It must be an address the key may send as, otherwise 403 from_address_forbidden.

tostring or dictionary or listObligatorio

One recipient or a list: an address string, a dictionary with email and name, or a list of either. to, cc and bcc together hold at most 50 addresses, and more is a 422 too_many_recipients.

ccstring or dictionary or list

Copy recipients, in the same forms as to, counted toward the 50 recipient ceiling.

bccstring or dictionary or list

Blind copy recipients, in the same forms as to, counted toward the 50 recipient ceiling.

replyTostring or dictionary

One address, as a string or a dictionary with email and name, written into the Reply-To header.

subjectstring

At most 998 characters. Falls back to the template or draft subject when empty.

htmlstring

HTML body, at most 1,000,000 characters.

textstring

Plain text body, at most 1,000,000 characters.

templatedictionary

A stored template as a dictionary with id, its id or slug, and optionally version, props and slots. Omitting version takes whatever is published at that moment, so pin it when somebody else owns the copy.

draftIdstring

Sends an existing draft as written. Cannot be combined with template or translate.

threadIdstring

Files the sent message into an existing thread.

headersdictionary

Custom headers as a dictionary of name to value, limited to X-*, List-*, Reply-To, Precedence, Auto-Submitted, Importance, Priority and Feedback-ID. Anything the server sets itself is a 422 reserved_header.

attachmentslist

At most 20 files, each a dictionary. An inline file has filename, content and optionally contentType, where content is base64 text, or a byte[] or a readable Stream that the SDK reads and encodes for you. Inline files are capped at 5 MB in total once decoded. A stored file is new Body { ["fileId"] = file["id"] }, naming a file already uploaded to the workspace, which is how a file larger than the inline cap is sent. A content string that is not base64 throws an ArgumentException before anything is sent, so encode raw bytes with OpenEmailClient.ToBase64.

attachmentDeliverystring

How the files in attachments travel. mime carries them inside the message, so a file over 5 MB is refused. link uploads each file and puts a download link in the body in its place, so the message itself stays small. auto links only when the from domain has an active files domain and the files together come to more than 2 MB, and attaches them otherwise, so nothing changes for a domain with no files domain set up. Left out, the sender's mailbox setting applies, and that defaults to auto.

scheduledAtDateTimeOffset or string

A DateTimeOffset, an ISO 8601 instant or a duration such as PT1H or P2D. At least one second and at most 365 days out.

cancellableForSecondsint

An undo window from 0 to 900 seconds on an immediate send. Refused alongside scheduledAt, which is already cancellable until it goes.

trackingdictionary

Overrides the tracking setting for this send, a dictionary with opens and clicks, both booleans. A field left out takes the setting of the address it is sent from: its own, else its domain catch-all's when the catch-all caught that address, else off.

signaturebool

An html body goes out exactly as written, so it carries a signature only when this is true, while a text-only body carries one unless this is false. When it is added it is the signature of the address it is sent from: its own, else its domain catch-all's when the catch-all caught that address, else the OpenEmail footer unless that address turned the footer off. Template sends and encrypted sends never carry one.

tagsdictionary

Up to 10 tags as a dictionary of key to value, keys of 1 to 64 letters, digits, _ or -, values up to 256 characters. Echoed back on every read.

translatedictionary

A dictionary with to, and optionally from, includeOriginal and subject. to takes a code, an English name or an endonym. includeOriginal and subject both default to true.

idempotencyKeystring?

Your own key, 1 to 255 characters of letters, digits, _, ., : or -. Anything else is a 400 invalid_idempotency_key.

apiKeystring?

Sends with this key instead of the client's, for a process sending on behalf of several workspaces.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A JsonObject for the message plus replayed. Notable fields are id (msg_ plus 24 hex), status, mode, from, subject, scheduledAt, cancellableUntil, sentAt, lastError, tags and, on a translated send, translation.

Ejemplo

await using var invoice = File.OpenRead("invoice.pdf"); var sent = await client.Emails.SendAsync(new Body{    ["from"] = "Acme Billing <[email protected]>",    ["to"] = "[email protected]",    ["subject"] = "Your September invoice",    ["html"] = "<p>The invoice is attached. Tell me if anything on it looks wrong.</p>",    ["attachments"] = new[] { new Body { ["filename"] = "invoice.pdf", ["content"] = invoice } },    ["translate"] = new Body { ["to"] = "de" },    ["tags"] = new Body { ["invoice"] = "inv_2026_09_4192" },}, idempotencyKey: "invoice:inv_2026_09_4192"); Console.WriteLine($"{sent["id"]} is {sent["status"]}{((bool?)sent["replayed"] == true ? ", replayed" : "")}");Console.WriteLine($"Sent in {sent["translation"]?["language"]?.ToString() ?? "the original language"}");

Notas

  • A from on a domain that is known to the workspace but cannot sign mail yet is refused up front with 409 domain_not_sendable and param set to from, so nothing is accepted that would only fail at dispatch. Addresses.ListAsync shows the same verdict as canSend before you send.

  • A test key (oe_test_) never delivers. The message is marked sent with transport set to test and every recipient delivered, so assert on the response and not on an inbox.

  • The idempotency fingerprint covers the template version the send resolved to. Retrying an unpinned template send after somebody publishes a new version is a 422 idempotency_key_reuse, not a replay. scheduledAt is left out of the fingerprint.

  • A spent send allowance is a 429 send_quota_exceeded with no Retry-After, and it resets on the first of the month. The SDK does not retry a 429 that carries no Retry-After, so it throws straight away.

  • Translation failures refuse the send: 409 translation_not_configured when the workspace has no AI, 422 translation_too_long past 30,000 characters, 429 ai_quota_exceeded when the workspace has used today's AI actions, and 503 translation_failed when the provider did not answer.

  • A translated send spends one AI action. IsRetryable is true for every 429, but ai_quota_exceeded fails the same way until the allowance resets at midnight UTC, so show it to a person or send without translate.

También disponible en

API
POST /emails
TypeScript
emails.send()
Python
emails.send()
Ruby
emails.send
PHP
emails->send
Go
Emails.Send
Java
emails().send
CLI
openemail emails send

Emails.SendBatchAsync

Send up to 100 independent emails in one request

Alcancesemails:send
Firma
Task<BatchResult> SendBatchAsync(    IEnumerable<IReadOnlyDictionary<string, object?>> emails,    string? idempotencyKey = null,    string? apiKey = null,    CancellationToken cancellationToken = default)

Sends each message in order, as if Emails.SendAsync had been called for it, and reports per item. It is never all or nothing: a bad address on item 7 fails item 7 and the rest still go, because a batch that rolled back would turn your retry into a guess about which messages had already been delivered. The call returns whenever the batch was processed, so check failed and each item's status rather than relying on an exception.

The batch shares one Idempotency-Key, generated once per call or supplied as idempotencyKey:, and the server derives a separate key per item from it and the item's position. Retrying the same list replays the items that already went and sends only the ones that did not. Reordering the list between attempts changes which body each position's key is bound to, so an item that moved comes back as an idempotency_key_reuse error.

Apart from a key or scope failure or a server fault, only problems with the batch as a whole throw, with a 422: an empty list, more than 100 messages, or more than 10 messages carrying translate. Translation costs several model calls per message and they run one after another, so a larger translated batch would time out partway. Split it, or schedule the messages instead.

Parámetros

emailsIEnumerable<IReadOnlyDictionary<string, object?>>Obligatorio

A list of between 1 and 100 messages, each a dictionary shaped exactly like the body of Emails.SendAsync and validated on its own. An entry that is not a dictionary throws an ArgumentException before anything is sent.

idempotencyKeystring?

Your own batch key, 1 to 255 characters of letters, digits, _, ., : or -.

apiKeystring?

Sends the batch with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A BatchResult with sent, failed and items, which a foreach over the result walks too. Each item is an object with its index and either status set to ok with the email, shaped like what Emails.SendAsync returns, or status set to error with an error carrying type, code, message and, when a field is to blame, param.

Ejemplo

var result = await client.Emails.SendBatchAsync(new[]{    new Body    {        ["from"] = "[email protected]",        ["to"] = "[email protected]",        ["subject"] = "Order AC-4192 has shipped",        ["text"] = "It is on its way.",    },    new Body    {        ["from"] = "[email protected]",        ["to"] = "[email protected]",        ["subject"] = "Order AC-4193 has shipped",        ["text"] = "It is on its way.",    },}, idempotencyKey: "shipments:2026-09-15"); Console.WriteLine($"{result.Sent} sent, {result.Failed} failed"); foreach (var item in result){    if ((string?)item["status"] == "error")    {        Console.WriteLine($"Item {item["index"]}: {item["error"]?["code"]} {item["error"]?["message"]}");    }}

Notas

  • Each entry is authorised on its own, so a from on a domain that cannot sign yet fails that entry with domain_not_sendable while the rest go.

  • Once the send allowance of the workspace runs out partway, every remaining item fails with send_quota_exceeded while the earlier ones stay sent. It is counted for that workspace alone, so sends from other workspaces never spend it. A workspace on a paid plan with pay as you go turned on keeps sending past it instead.

  • Each item with translate spends one AI action. Once that account has used today's AI actions, every remaining item with translate fails with ai_quota_exceeded while items without it still go. Retrying those items fails the same way until the allowance resets at midnight UTC, unless the account has pay as you go turned on.

  • An unexpected server fault aborts the batch with a 500 after the earlier items have gone. The SDK retries it with the same key, which replays those items instead of sending them twice.

  • Items are processed one after another inside a single request, so a large batch of immediate sends takes noticeably longer than one Emails.SendAsync. Keep the client's timeout generous.

También disponible en

API
POST /emails/batch
TypeScript
emails.sendBatch()
Python
emails.send_batch()
Ruby
emails.send_batch
PHP
emails->sendBatch
Go
Emails.SendBatch
Java
emails().sendBatch
CLI
openemail emails send-batch

Emails.TranslateAsync

Preview a translation without sending anything

Alcancesemails:send
Firma
Task<JsonObject> TranslateAsync(    IReadOnlyDictionary<string, object?> body,    string? apiKey = null,    CancellationToken cancellationToken = default)

Runs the same translation the translate field performs on a send and stops one step early. The same function produces both, so what comes back is what would go out. Nothing is stored and nothing is sent. Use it when somebody should read the translated wording before it reaches a recipient.

Send the approved result as an ordinary subject and html on Emails.SendAsync with no translate field. Passing translate again translates a second time, moving the wording off the version that was signed off and discarding any edits. When includeOriginal is on, html already contains your original text below the translation, so do not append your own copy.

At least one of html, text or subject is required. to accepts a BCP-47 code, an English name or the language's own name, and the response reports the code it settled on in preview["language"]["code"], which is the form worth storing. State from to skip language detection. Otherwise it is detected from the body, and a detector that cannot tell returns null in detectedSourceLanguage rather than guessing.

Parámetros

tostringObligatorio

Target language as a code (de), English name (German) or endonym (Deutsch). An unrecognised value is a 422 invalid_parameter on to.

fromstring

The language you wrote in. Stating it skips the detection call.

includeOriginalbool

Defaults to true, placing your original text below the translation under a caption in the target language.

subjectstring

Subject line to translate, at most 998 characters.

htmlstring

HTML body to translate. Only the content inside <body> is sent to the model when the markup is a full document.

textstring

Plain text body to translate. Translated separately when given alongside html.

apiKeystring?

Runs the preview with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A JsonObject with object set to translation, language and detectedSourceLanguage as full language objects (code, label, native, flag and rtl), subject, html and text (each null when that input was not given) and includeOriginal.

Ejemplo

var preview = await client.Emails.TranslateAsync(new Body{    ["to"] = "ja",    ["subject"] = "Your September invoice",    ["html"] = "<p>The invoice is attached.</p>",}); Console.WriteLine($"{preview["language"]?["native"]}, translated from {preview["detectedSourceLanguage"]?["code"]?.ToString() ?? "an unknown language"}"); await client.Emails.SendAsync(new Body{    ["from"] = "Acme Billing <[email protected]>",    ["to"] = "[email protected]",    ["subject"] = preview["subject"],    ["html"] = preview["html"],});

Notas

  • The SDK never retries this call. Each attempt spends one AI action, as a translated send does. Handle a 503 translation_failed yourself, and treat a 429 ai_quota_exceeded as final until the allowance resets at midnight UTC.

  • Anything over 30,000 characters is refused with 422 translation_too_long rather than truncated, since half a translation has no seam to show where it stopped.

  • A right-to-left target comes back with html wrapped in dir="rtl".

  • A workspace with no AI configured gets 409 translation_not_configured, and retrying will fail the same way.

También disponible en

API
POST /emails/translate
TypeScript
emails.translate()
Python
emails.translate()
Ruby
emails.translate
PHP
emails->translate
Go
Emails.Translate
Java
emails().translate
CLI
openemail emails translate

Emails.CheckAsync

Check how a message would be rated, without sending it

Alcancesemails:send
Firma
Task<JsonObject> CheckAsync(    IReadOnlyDictionary<string, object?> body,    string? apiKey = null,    CancellationToken cancellationToken = default)

Scores a message the way a receiving mailbox would, before it goes out: a spam score, a phishing score and an AI-writing score, each 0 to 100, with the signals behind each one. Nothing is stored and nothing is sent.

The same checks score every message that arrives in an OpenEmail mailbox, so what comes back is what an OpenEmail recipient sees in Details. It cannot know a recipient's own filter, sender history or reputation, so a low score is a good sign and not a delivery guarantee.

Run it before an automated send, or as someone writes, and fix what signals names. Sender authentication is taken as passing, since the message will be signed for your domain.

Parámetros

subjectstring

Subject line, at most 998 characters.

htmlstring

HTML body. Links and images are read from it.

textstring

Plain text body. Taken from html when left out.

fromstring

The address it will be sent from.

fromNamestring

The display name it will carry. A name that claims another address or a known brand raises the phishing score.

replyTostring

A Reply-To on a different domain raises the phishing score.

replyingbool

True when it answers an existing thread. A Re: subject on a message that answers nothing raises the spam score.

attachmentNamesIEnumerable<string>

File names, so an attachment that can run code is caught.

apiKeystring?

Runs the check with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A JsonObject with object set to email_check and three scores. spam carries score, level (low, medium from 35, high from 60) and signals. phishing carries score, level (clear, caution from 30, danger from 60), signals and reasons. ai carries score (null when not judged), level, signals, reasons, words and skipped (too-short under 40 words).

Ejemplo

var check = await client.Emails.CheckAsync(new Body{    ["from"] = "[email protected]",    ["subject"] = "Your September invoice",    ["html"] = "<p>The invoice is attached.</p>",    ["attachmentNames"] = new[] { "invoice.pdf" },}); if ((string?)check["spam"]?["level"] != "low"){    Console.WriteLine($"Rework it first: {string.Join("; ", check["spam"]?["signals"]?.AsArray() ?? [])}");}

Notas

  • It spends no AI action and never calls a model, so it is safe to run on every revision.

  • A score is not a probability. Each one adds up weighted signals, heaviest first in signals.

También disponible en

API
POST /emails/check
TypeScript
emails.check()
Python
emails.check()
Ruby
emails.check
PHP
emails->check
Go
Emails.Check
Java
emails().check
CLI
openemail emails check

Emails.ListAsync

List one page of sent emails, newest first

Alcancesemails:readRecorre los resultados por páginas
Firma
Task<Page> ListAsync(    IEnumerable<string>? status = null,    string? from = null,    string? broadcastId = null,    DateTimeOffset? scheduledFrom = null,    DateTimeOffset? scheduledTo = null,    int? limit = null,    string? cursor = null,    string? apiKey = null,    CancellationToken cancellationToken = default)

Returns one page of the workspace's send records, ordered newest first. Paging is keyset rather than offset: nextCursor is the id of the last message on the page, and passing it back as cursor: continues strictly after it, so messages sent while you page never shift or repeat rows. hasMore is false on the last page and nextCursor is then null.

Filter with status:, one value or an object that the SDK joins with commas, with from:, which matches the sending address exactly and ignores case, with broadcastId:, which keeps the copies of one broadcast, and with scheduledFrom: and scheduledTo:, which keep the messages scheduled inside a window. An unrecognised status is a 422 invalid_parameter naming the offending values, and a cursor that names no message in the workspace is a 400 invalid_cursor.

Rows are the summary form. They never carry recipients or translation, whose absence on a row says nothing either way, and a tracked message carries only the counts half of tracking: opens, clicks, opened, clicked, openCount, clickCount and firstOpenAt. Call Emails.GetAsync for per-recipient delivery state and Emails.GetTrackingAsync for the full engagement report.

Parámetros

statusIEnumerable<string>?

One or more of queued, scheduled, sending, sent, partial, bounced, cancelled and failed.

fromstring?

A bare sending address such as [email protected], matched exactly and case insensitively. A display name form does not match.

broadcastIdstring?

Only the copies of one broadcast, a brd_ id from Broadcasts.SendAsync. Each person a broadcast reaches gets a message of their own, so this lists who it went to and what happened to each copy. An id that names no broadcast answers an empty page.

scheduledFromDateTimeOffset?

Only messages scheduled for this instant or later. With scheduledTo: and status: new[] { "scheduled", "queued" } it lists what is waiting to go out in a window, as the calendar of the app does. A message with no scheduledAt is left out.

scheduledToDateTimeOffset?

Only messages scheduled for this instant or earlier. scheduledFrom: after scheduledTo: is a 422 invalid_parameter.

limitint?

Rows per page, a whole number from 1 to 100, defaulting to 25. Outside that range is a 422.

cursorstring?

The nextCursor from the previous page, which is a message id.

apiKeystring?

Lists with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A Page of message objects, with items, hasMore and nextCursor. Each item has id, status, mode, from, subject, transport, attempts, lastError, scheduledAt, cancellableUntil, sentAt, tags, broadcastId, source, createdAt and, when tracked, the trimmed tracking counts.

Ejemplo

var page = await client.Emails.ListAsync(status: new[] { "failed", "partial" }, from: "[email protected]", limit: 50); foreach (var email in page){    Console.WriteLine($"{email["id"]} {email["status"]} {email["lastError"]}");} if (page.HasMore){    var next = await client.Emails.ListAsync(status: new[] { "failed", "partial" }, from: "[email protected]", limit: 50, cursor: page.NextCursor);     Console.WriteLine($"{next.Count} more on the next page");}

Notas

  • With a narrowed key only messages sent from addresses it covers are read, and the page is cut after that filter, so every page but the last holds limit: items. A key that holds a whole domain covers every address on it.

  • A from: the key does not cover returns an empty last page rather than a 403.

  • tracking is absent, not zeroed, on a message that carried no pixel or rewritten link.

También disponible en

API
GET /emails
TypeScript
emails.list()
Python
emails.list()
Ruby
emails.list
PHP
emails->list
Go
Emails.List
Java
emails().list
CLI
openemail emails list

Emails.ListAllAsync

Collect every matching sent email into one object

Alcancesemails:readRecorre los resultados por páginas
Firma
Task<IReadOnlyList<JsonObject>> ListAllAsync(    IEnumerable<string>? status = null,    string? from = null,    string? broadcastId = null,    DateTimeOffset? scheduledFrom = null,    DateTimeOffset? scheduledTo = null,    int? limit = null,    string? cursor = null,    string? apiKey = null,    CancellationToken cancellationToken = default)

Follows nextCursor from page to page and returns once the last page has been read, with every matching send record in one object, newest first. It accepts the same filters as Emails.ListAsync and returns the same summary rows, so there are no recipients or translation on them and tracking is the trimmed counts form.

Everything is held in memory before the call returns, and a workspace's send history grows without bound. Narrow it with status: or from:, or switch to Emails.IterateAsync when you want to stop early or process rows as they arrive. limit: sets the page size of each underlying request, not the total, so a larger value means fewer round trips.

Parámetros

statusIEnumerable<string>?

One or more statuses to keep, joined with commas on the wire.

fromstring?

A bare sending address, matched exactly and case insensitively.

broadcastIdstring?

Only the copies of one broadcast, a brd_ id.

scheduledFromDateTimeOffset?

Only messages scheduled for this instant or later.

scheduledToDateTimeOffset?

Only messages scheduled for this instant or earlier.

limitint?

Page size per request, from 1 to 100, defaulting to 25 on the server.

cursorstring?

A message id to start after, skipping everything newer.

apiKeystring?

Lists with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A list of message objects holding every row across all pages.

Ejemplo

var waiting = await client.Emails.ListAllAsync(status: new[] { "scheduled", "queued" }, scheduledFrom: DateTimeOffset.UtcNow.Date, scheduledTo: DateTimeOffset.UtcNow.Date.AddDays(1), limit: 100); foreach (var email in waiting){    Console.WriteLine($"{email["scheduledAt"]} {email["subject"]}");}

Notas

  • A failure on any page throws out of the whole call, and the rows already fetched are discarded.

  • With a narrowed key only messages sent from addresses it covers are collected, and every page but the last is full.

También disponible en

API
GET /emails
TypeScript
emails.listAll()
Python
emails.list_all()
Ruby
emails.list_all
PHP
emails->listAll
Go
Emails.ListAll
Java
emails().listAll

Emails.IterateAsync

Stream sent emails one at a time across pages

Alcancesemails:readRecorre los resultados por páginas
Firma
IAsyncEnumerable<JsonObject> IterateAsync(    IEnumerable<string>? status = null,    string? from = null,    string? broadcastId = null,    DateTimeOffset? scheduledFrom = null,    DateTimeOffset? scheduledTo = null,    int? limit = null,    string? cursor = null,    string? apiKey = null,    CancellationToken cancellationToken = default)

Returns an IAsyncEnumerable<JsonObject> that yields send records one at a time, newest first, and requests the next page only once the current one is used up. Nothing is fetched until the loop starts, and breaking out of the await foreach stops the requests, so this is the cheapest way to find the most recent message matching a condition the filters cannot express.

The walk is keyset based, following nextCursor from page to page. Mail sent while you iterate lands ahead of where you started and is never yielded, and nothing already yielded comes round again. Rows are the same summary form Emails.ListAsync returns.

Parámetros

statusIEnumerable<string>?

One or more statuses to keep, joined with commas on the wire.

fromstring?

A bare sending address, matched exactly and case insensitively.

broadcastIdstring?

Only the copies of one broadcast, a brd_ id.

scheduledFromDateTimeOffset?

Only messages scheduled for this instant or later.

scheduledToDateTimeOffset?

Only messages scheduled for this instant or earlier.

limitint?

Page size per request, from 1 to 100, defaulting to 25 on the server.

cursorstring?

A message id to start after.

apiKeystring?

Lists with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

An IAsyncEnumerable<JsonObject> that yields one message per step.

Ejemplo

await foreach (var email in client.Emails.IterateAsync(status: new[] { "failed" }, limit: 100)){    Console.WriteLine(email["id"]);}

Notas

  • The generator is lazy, so an abandoned loop costs only the pages you consumed.

  • With a narrowed key only messages sent from addresses it covers are yielded, and every page but the last is full.

También disponible en

API
GET /emails
TypeScript
emails.iterate()
Python
emails.iterate()
Ruby
emails.iterate
PHP
emails->iterate
Go
Emails.Iterate
Java
emails().iterate

Emails.GetAsync

Read one sent email with per-recipient state

Alcancesemails:read
Firma
Task<JsonObject> GetAsync(    string id,    string? apiKey = null,    CancellationToken cancellationToken = default)

Returns the full send record for one message: its lifecycle status, delivery attempts and lastError, the schedule fields, and the two parts a list row leaves out. recipients has one entry per address with its own status, error and deliveredAt, and translation records what was done to a translated send.

A message that went out as a single call can still land differently per recipient. status on the message says how the send went as a whole, while each recipient moves on as delivery reports, bounces and complaints arrive. uncertain is a real recipient state: a transport that failed partway cannot say which recipients it reached. suppressed marks an address that previously bounced or complained in this workspace and was held back.

When the message was tracked, tracking carries the full engagement report with per-recipient and per-link detail. When it was not tracked, the field is absent rather than zeroed, because a message with no pixel has no evidence about whether anybody read it.

Parámetros

idstringObligatorio

The send id, msg_ followed by 24 hex characters, as returned by Emails.SendAsync.

apiKeystring?

Reads with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A JsonObject with id, status, mode, from, subject, threadId, transport, attempts, lastError, scheduledAt, cancellableUntil, sentAt, tags, broadcastId, source, createdAt, recipients and, when present, translation and the full tracking report.

Ejemplo

var email = await client.Emails.GetAsync("msg_3f9a1c07d2b84e6a9c5b1f20"); Console.WriteLine($"{email["subject"]}: {email["status"]}"); foreach (var recipient in email["recipients"]?.AsArray() ?? []){    if ((string?)recipient?["status"] != "delivered")    {        Console.WriteLine($"  {recipient?["email"]} {recipient?["status"]} {recipient?["error"]}");    }}

Notas

  • Do not correlate on messageId. The header is rewritten on the way out, so that value appears in no bounce or delivery report. Webhook events name the send by this id, as emailId.

  • A 404 never distinguishes a missing id from one in another workspace, and a narrowed key gets the same 404 for a message sent from an address it does not cover.

  • transport stays null until dispatch, and reads test on every message sent with a test key.

También disponible en

API
GET /emails/{id}
TypeScript
emails.get()
Python
emails.get()
Ruby
emails.get
PHP
emails->get
Go
Emails.Get
Java
emails().get
CLI
openemail emails get

Emails.ListEventsAsync

Read one page of the event trail of one sent email

Alcancesemails:readRecorre los resultados por páginas
Firma
Task<Page> ListEventsAsync(    string id,    int? limit = null,    string? cursor = null,    string? apiKey = null,    CancellationToken cancellationToken = default)

Returns one page of everything recorded against one send, oldest first. Nothing is dropped from the trail, so following nextCursor while hasMore is true reaches its newest event, and Emails.ListAllEventsAsync and Emails.IterateEventsAsync do that walk for you. It is the audit behind the current status: when the message was accepted or held, when it was rescheduled or cancelled, when it went out or failed, and every delivery report, bounce, complaint, open, click and file download attributed to it afterwards.

Each event has a dotted type and a data object whose shape depends on it. email.accepted, email.queued and email.scheduled open the trail with the source and recipient count. email.sent names the transport and messageId. email.failed carries the error. email.bounced and email.complained list the affected recipients and whether they were suppressed. email.delivered, email.rescheduled, email.cancelled, email.opened, email.clicked and email.downloaded follow as they happen. email.downloaded counts a person fetching a file that went out as a download link, never a scanner, and carries no recipient: the link is the same for everyone the message went to, so a download cannot be attributed. data is an empty object when an event carries nothing.

Webhooks deliver a subset of these same events as they occur, so this is where to look when a webhook was missed or never subscribed.

Parámetros

idstringObligatorio

The msg_ send id whose trail to read.

limitint?

Events per page, a whole number from 1 to 100, defaulting to 25.

cursorstring?

The nextCursor from the previous page, which is an event id. One that names no event of this send is a 400 invalid_cursor.

apiKeystring?

Reads with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A Page of event objects, with items, hasMore and nextCursor. Each item has object set to event, id, type, data and createdAt.

Ejemplo

var page = await client.Emails.ListEventsAsync("msg_3f9a1c07d2b84e6a9c5b1f20", limit: 100); foreach (var entry in page){    Console.WriteLine($"{entry["createdAt"]} {entry["type"]}");     if ((string?)entry["type"] == "email.bounced")    {        Console.WriteLine(entry["data"]);    }}

Notas

  • email.delivered is recorded in this trail but is never sent as a webhook, so a delivery report surfaces only here and in recipients on Emails.GetAsync.

  • A send made with a test key records email.sent with transport set to test and simulated set to true in data.

  • An unknown id is a 404, never an empty page.

  • A tracked message opened or clicked many times records one event per counted hit, so its trail can run to many pages.

También disponible en

API
GET /emails/{id}/events
TypeScript
emails.listEvents()
Python
emails.list_events()
Ruby
emails.list_events
PHP
emails->listEvents
Go
Emails.ListEvents
Java
emails().listEvents
CLI
openemail emails list-events

Emails.ListAllEventsAsync

Collect the whole event trail of one sent email into one object

Alcancesemails:readRecorre los resultados por páginas
Firma
Task<IReadOnlyList<JsonObject>> ListAllEventsAsync(    string id,    int? limit = null,    string? cursor = null,    string? apiKey = null,    CancellationToken cancellationToken = default)

Walks every page of one send's event trail and returns all of it, oldest first: acceptance, scheduling, sending, every delivery report, bounce and complaint, and every counted open, click and download afterwards.

A widely read message can hold a great many events, all in memory before the call returns. Prefer Emails.IterateEventsAsync when you can stop early. limit: sets the page size of each request, not the total.

Parámetros

idstringObligatorio

The msg_ send id whose trail to read.

limitint?

Page size per request, from 1 to 100, defaulting to 25 on the server.

cursorstring?

An event id to start after, skipping every older event.

apiKeystring?

Reads with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A list of event objects holding every event across all pages, oldest first.

Ejemplo

var events = await client.Emails.ListAllEventsAsync("msg_3f9a1c07d2b84e6a9c5b1f20", limit: 100); Console.WriteLine(events.Count);

Notas

  • A failure on any page throws out of the whole call, and the events already fetched are discarded.

  • An unknown id is a 404 on the first page.

También disponible en

API
GET /emails/{id}/events
TypeScript
emails.listAllEvents()
Python
emails.list_all_events()
Ruby
emails.list_all_events
PHP
emails->listAllEvents
Go
Emails.ListAllEvents
Java
emails().listAllEvents

Emails.IterateEventsAsync

Stream the event trail of one sent email one event at a time

Alcancesemails:readRecorre los resultados por páginas
Firma
IAsyncEnumerable<JsonObject> IterateEventsAsync(    string id,    int? limit = null,    string? cursor = null,    string? apiKey = null,    CancellationToken cancellationToken = default)

Returns an IAsyncEnumerable<JsonObject> over one send's event trail that yields events one at a time, oldest first, and fetches the next page only when the current one is used up. Nothing is requested until the loop starts, and breaking out of the await foreach stops further requests.

The walk moves forward in time, so events recorded while you iterate are yielded when the walk reaches them, and it ends when hasMore is false.

Parámetros

idstringObligatorio

The msg_ send id whose trail to read.

limitint?

Page size per request, from 1 to 100, defaulting to 25 on the server.

cursorstring?

An event id to start after, skipping every older event.

apiKeystring?

Reads with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

An IAsyncEnumerable<JsonObject> that yields one event per step.

Ejemplo

await foreach (var entry in client.Emails.IterateEventsAsync("msg_3f9a1c07d2b84e6a9c5b1f20")){    if ((string?)entry["type"] == "email.delivered")    {        Console.WriteLine($"Delivered at {entry["createdAt"]}");         break;    }}

Notas

  • The generator is lazy, so an abandoned loop costs only the pages you consumed.

También disponible en

API
GET /emails/{id}/events
TypeScript
emails.iterateEvents()
Python
emails.iterate_events()
Ruby
emails.iterate_events
PHP
emails->iterateEvents
Go
Emails.IterateEvents
Java
emails().iterateEvents

Emails.GetTrackingAsync

Read the engagement report for a sent email

Alcancesemails:read
Firma
Task<JsonObject> GetTrackingAsync(    string id,    string? apiKey = null,    CancellationToken cancellationToken = default)

Returns the same document Tracking.GetAsync serves, reached from the msg_ id a sender already holds. It has the message totals, one entry per tracked copy under recipients, and every rewritten link with its clicks under links.

A message that was never tracked is a 404 here rather than an empty report. "We were not recording" and "nobody opened it" are different answers, and a client that renders them the same way makes a claim about a reader on no evidence. Tracking applies per send: opens and clicks record what was applied when the message went out, resolved from the setting of the address it was sent from (its own, else its domain catch-all's when the catch-all caught that address, else off) and any tracking override on the send, not what is switched on now.

Read every count as a floor. An open is inferred from a mail client fetching an image, so a reader whose client blocks images is never counted, and Gmail fetches the image once through its proxy and serves later views from cache. A click is stronger evidence than an open.

Parámetros

idstringObligatorio

The msg_ send id returned by Emails.SendAsync.

apiKeystring?

Reads with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A JsonObject with object set to tracking, id (the tmsg_ tracking id), sendId, opens, clicks, opened, clicked, attributable, openCount, clickCount, openCountRaw, clickCountRaw, the first and last open and click times, recipients and links.

Ejemplo

try{    var report = await client.Emails.GetTrackingAsync("msg_3f9a1c07d2b84e6a9c5b1f20");     Console.WriteLine($"Opened at least {report["openCount"]} times, clicked {report["clickCount"]}");     if ((bool?)report["attributable"] == true)    {        foreach (var recipient in report["recipients"]?.AsArray() ?? [])        {            if ((bool?)recipient?["attributed"] == true && (int?)recipient?["openCount"] == 0)            {                Console.WriteLine($"{recipient?["email"]} has not opened it");            }        }    }}catch (OpenEmailApiException error) when (error.IsNotFound){    Console.WriteLine("This message was not tracked");}

Notas

  • Only claim a named recipient has not opened when attributable is true. Mail that went to the whole list as one body has a shared copy whose email is null, and its opens cannot be pinned to anybody.

  • A message sent with a test key is never tracked, so this is always a 404 for one.

  • openCountRaw - openCount includes machine fetches such as Apple Mail Privacy Protection and repeats within thirty seconds, so do not read the difference as a pure machine count.

También disponible en

API
GET /emails/{id}/tracking
TypeScript
emails.getTracking()
Python
emails.get_tracking()
Ruby
emails.get_tracking
PHP
emails->getTracking
Go
Emails.GetTracking
Java
emails().getTracking
CLI
openemail emails get-tracking

Emails.CancelAsync

Stop a queued or scheduled email before it goes

Alcancesemails:send
Firma
Task<JsonObject> CancelAsync(    string id,    string? apiKey = null,    CancellationToken cancellationToken = default)

Cancels a message that has not been dispatched yet: a send held by scheduledAt, or an immediate send still inside its cancellableForSeconds undo window. The message moves to cancelled, nothing is delivered, and an email.cancelled event is recorded and sent to subscribed webhooks.

Only queued and scheduled messages can be cancelled. Once a message is sending, sent, partial, bounced or failed the call is a 409 email_not_cancellable, since there is no pending dispatch left to stop and mail that has gone cannot be recalled. An immediate send with no undo window is dispatched inside the Emails.SendAsync request, so by the time you hold its id it is usually past this point.

Cancelling is idempotent. Cancelling an already cancelled message returns the same cancelled message rather than an error, and the SDK retries the call after a network failure or a retryable status.

Parámetros

idstringObligatorio

The msg_ send id to cancel.

apiKeystring?

Cancels with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A JsonObject for the message in its new state, with status set to cancelled and scheduledAt and cancellableUntil still showing when it would have gone.

Ejemplo

var email = await client.Emails.SendAsync(new Body{    ["from"] = "[email protected]",    ["to"] = "[email protected]",    ["subject"] = "Your September invoice",    ["text"] = "The invoice is attached.",    ["cancellableForSeconds"] = 30,}); try{    var cancelled = await client.Emails.CancelAsync(email["id"]!.GetValue<string>());     Console.WriteLine($"{cancelled["id"]} is {cancelled["status"]}");}catch (OpenEmailApiException error) when (error.IsConflict){    Console.WriteLine("Too late, it has gone");}

Notas

  • cancellableUntil on the message is the moment it stops being cancellable. Past it, expect the 409.

  • A cancelled message stays cancelled. There is no way to resume it, so send again if you change your mind.

  • A narrowed key gets a 404 for a message sent from an address it does not cover.

También disponible en

API
POST /emails/{id}/cancel
TypeScript
emails.cancel()
Python
emails.cancel()
Ruby
emails.cancel
PHP
emails->cancel
Go
Emails.Cancel
Java
emails().cancel
CLI
openemail emails cancel

Emails.RescheduleAsync

Move a queued or scheduled email to a new send time

Alcancesemails:send
Firma
Task<JsonObject> RescheduleAsync(    string id,    DateTimeOffset scheduledAt,    string? apiKey = null,    CancellationToken cancellationToken = default)

Changes when a message that has not gone yet will be dispatched. scheduledAt is the only thing this call can change, and the SDK sends nothing else: the body, recipients and any translation stay exactly as they were accepted.

The new time takes a DateTimeOffset. To move a send by a duration such as PT30M or P2D, measured from when the server receives the request, pass it as scheduledAt to Emails.UpdateAsync. It must be at least one second in the future and at most 365 days out, otherwise the call is a 422 on scheduledAt, usually invalid_parameter. Earlier and later times are both allowed.

Only queued and scheduled messages can be moved. Anything already sending, sent, partial, bounced, cancelled or failed is a 409 email_not_cancellable. A queued message inside its undo window can be rescheduled too, which turns it into a scheduled send that stays cancellable until the new time.

Parámetros

idstringObligatorio

The msg_ send id to move.

scheduledAtDateTimeOffsetObligatorio

The new send time, a DateTimeOffset, sent as an ISO 8601 instant in UTC.

apiKeystring?

Reschedules with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A JsonObject for the message with status set to scheduled and scheduledAt and cancellableUntil both set to the new time.

Ejemplo

var berlin = TimeZoneInfo.FindSystemTimeZoneById("Europe/Berlin");var today = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, berlin).Date;var monday = today.AddDays(((int)DayOfWeek.Monday - (int)today.DayOfWeek + 7) % 7 + 7).AddHours(9); var email = await client.Emails.RescheduleAsync("msg_3f9a1c07d2b84e6a9c5b1f20", new DateTimeOffset(monday, berlin.GetUtcOffset(monday))); Console.WriteLine($"{email["status"]} for {email["scheduledAt"]}"); await client.Emails.RescheduleAsync("msg_3f9a1c07d2b84e6a9c5b1f20", DateTimeOffset.UtcNow.AddMinutes(30));

Notas

  • The SDK retries this call after a network failure. A duration is resolved again on each attempt, so a retried PT1H lands an hour after the last attempt the server received.

  • An email.rescheduled event with the new scheduledAt is added to the trail on every successful move.

  • A translated scheduled message keeps its approved wording. To change the text itself, cancel it and send again.

También disponible en

API
PATCH /emails/{id}
TypeScript
emails.reschedule()
Python
emails.reschedule()
Ruby
emails.reschedule
PHP
emails->reschedule
Go
Emails.Reschedule
Java
emails().reschedule
CLI
openemail emails reschedule

Emails.UpdateAsync

Change an email that has not gone yet

Alcancesemails:send
Firma
Task<JsonObject> UpdateAsync(    string id,    IReadOnlyDictionary<string, object?> patch,    string? apiKey = null,    CancellationToken cancellationToken = default)

Changes a queued or scheduled message before it is dispatched: when it goes with scheduledAt, what it says with subject, html and text, the address it goes out as with from, and who it goes to with to, cc and bcc. Send any of them together, and a field you leave out keeps its value. This is what editing a scheduled message in the calendar of the app does.

A recipient list replaces the stored one whole, and takes a string such as Ada <[email protected]>, an object with email and name, or a list of either. from is checked as it is on a send, so it has to be an address the key may send as, or the call is a 403 from_address_forbidden.

Only messages that have not gone can change. Anything already sending, sent, partial, bounced, cancelled or failed is a 409 email_not_cancellable. A message translated when it was accepted keeps its approved wording, so a new subject, html or text on it is a 409 translation_locked, and one that was encrypted before it was scheduled keeps its wording and its recipients. Cancel those and send again instead.

Parámetros

idstringObligatorio

The msg_ send id to change.

scheduledAtDateTimeOffset or string

A new send time: a DateTimeOffset, an ISO 8601 instant or a duration such as PT2H, in the future and at most 365 days out.

subjectstring

The new subject, up to 998 characters.

htmlstring

The new HTML body.

textstring

The new plain text body.

fromstring

The address it goes out as instead, one the key may send as.

tostring or dictionary or list

Replaces the recipients, at least one and at most 50 across the three lists.

ccstring or dictionary or list

Replaces the copied recipients.

bccstring or dictionary or list

Replaces the blind copied recipients.

apiKeystring?

Changes it with this key instead of the client's.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A JsonObject for the message as it is now. Its subject, from and scheduledAt show the change.

Ejemplo

var email = await client.Emails.UpdateAsync("msg_3f9a1c07d2b84e6a9c5b1f20", new Body{    ["subject"] = "Your September invoice, corrected",    ["to"] = new object?[]    {        "[email protected]",        new Body { ["email"] = "[email protected]", ["name"] = "Grace Hopper" },    },    ["scheduledAt"] = DateTimeOffset.UtcNow.AddHours(2),}); Console.WriteLine($"{email["subject"]} goes at {email["scheduledAt"]}");

Notas

  • The SDK retries this call after a network failure, which is safe because a repeat writes the same values.

  • An email.updated event naming the changed fields is added to the trail, and a move adds email.rescheduled as well.

  • Emails.RescheduleAsync is the same call with only scheduledAt.

También disponible en

API
PATCH /emails/{id}
TypeScript
emails.update()
Python
emails.update()
Ruby
emails.update
PHP
emails->update
Go
Emails.Update
Java
emails().update
CLI
openemail emails update

Emails.ComposeAsync

Write an email with AI

Alcancesemails:send
Firma
Task<JsonObject> ComposeAsync(    IReadOnlyDictionary<string, object?> body,    string? apiKey = null,    CancellationToken cancellationToken = default)

Writes the body of an email from prompt, an instruction, a rough draft or a few notes, in the style of the mail this workspace has sent before, as the composer of the app does. subject, to and cc help the greeting and the tone fit, and from, the address it goes out as, has it written as that address.

Give threadId to write a reply: the messages of that thread are read as context, which also needs threads:read, and a key limited to particular addresses can only use a thread that arrived at them.

Give draft, the body written so far, and prompt says what to change in it, as the describe bar of the composer does. withSubject set to true adds subject to the answer. Give send, the send options as they stand, even [], and prompt may change the recipients, the send time, tracking, the signature and the language: the answer's send holds only what changed, in the shape Emails.SendAsync takes, and null takes an option away. Add send["fromOptions"], the addresses it may go out as, and prompt may move it to one of them, which the answer names in send["from"]. Add send["encrypt"], whether it is encrypted end to end as it stands, only when every recipient can receive encrypted mail, and prompt may turn encryption on or off. Times such as "tomorrow at 9" are read in timeZone, or the time zone of the account.

Give templates set to true and prompt may switch the email to one of the workspace's published templates, which the answer names in template: send that template with Emails.SendAsync in place of body, because its body replaces it. Give template, the id of the template the email uses now, and prompt leaves the body alone. Give files set to true and prompt may attach files the workspace holds, found by their name: the answer lists them in attach, each ready to send as new Body { ["fileId"] = file["id"] } in attachments, and names in attachMissing what matched no file. templates needs templates:read and files needs files:read, and each is ignored without its scope. A key limited to particular addresses only finds the files at those addresses.

Nothing is saved or sent. Pass body to Emails.SendAsync or Drafts.CreateAsync when it reads right. Each call spends one of the workspace's AI actions, and a workspace that has used them all for the day is refused with a 429 ai_quota_exceeded.

Parámetros

promptstringObligatorio

What to write, up to 20,000 characters. With draft, what to change in it, and it may be empty to have the draft finished as it is.

subjectstring

The subject so far, if there is one.

fromstring

The address it goes out as, so it is written as that address.

templatestring

The id of the template the email uses now, up to 128 characters. Its body is then the template, so prompt leaves the body alone.

templatesbool

Let prompt switch the email to one of the workspace's published templates, which the answer names in template. Needs templates:read, and without it this is ignored.

filesbool

Let prompt attach files the workspace holds, found by their name. The answer lists them in attach, each ready to send as new Body { ["fileId"] = file["id"] }, and what matched no file in attachMissing. Needs files:read, and without it this is ignored.

withSubjectbool

Also write a subject. The answer then carries subject.

draftstring

The body written so far, as text or Markdown, up to 20,000 characters.

toIEnumerable<string>

Who it goes to.

ccIEnumerable<string>

Who is copied.

bccIEnumerable<string>

Who is blind copied.

senddictionary

The send options as they stand: scheduledAt, tracking, signature, translate, fromOptions and encrypt, each optional. Give it, even [], to let prompt change them. fromOptions lists up to 100 addresses it may go out as, so prompt can move it to one of them, and encrypt says whether it is encrypted end to end: give it only when every recipient can receive encrypted mail, so prompt can turn encryption on or off.

timeZonestring

The IANA time zone to read times in, such as Europe/Berlin. Without it, the time zone of the account.

threadIdstring

A thread to reply in, read as context.

apiKeystring?

Overrides the client's API key for this call only.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A JsonObject with object set to composition and body, plus subject when asked with withSubject, send when send was given, template, attach and attachMissing when templates or files was given and prompt asked for them, note, a short sentence when part of prompt cannot be done this way, such as adding somebody whose address it was not given, and sources when the draft drew on the knowledge base. Its send can carry from, the address to send it from instead, one of send["fromOptions"], and encrypt, whether to encrypt it end to end, when send["encrypt"] was given. template holds the id and name of the template to send it with instead, whose body replaces body. attach lists the files to attach, each with id, filename, contentType and size in bytes, and attachMissing what prompt asked to attach that matched no file, as prompt named it. sources lists the knowledge base items it drew on, the pinned notes at the levels of the sending address and the items whose passages matched the request, each with id, title, kind (note, file or link), scope, the level it sits at, and url, the page a link reads or null.

Ejemplo

try{    var composition = await client.Emails.ComposeAsync(new Body    {        ["prompt"] = "Send Ada the signed contract and ask for the invoice by Friday.",        ["from"] = "[email protected]",        ["to"] = new[] { "[email protected]" },        ["withSubject"] = true,        ["files"] = true,    });}catch (OpenEmailApiException error){    if (error.Code != "ai_quota_exceeded")    {        throw;    }     Console.WriteLine("No AI actions left today");}

Notas

  • The SDK does not retry it, because a second call writes something different and spends a second AI action.

  • A server with no AI configured answers 409 ai_not_configured.

También disponible en

API
POST /emails/compose
TypeScript
emails.compose()
Python
emails.compose()
Ruby
emails.compose
PHP
emails->compose
Go
Emails.Compose
Java
emails().compose
CLI
openemail emails compose

Emails.RewriteAsync

Rewrite part of an email with AI

Alcancesemails:send
Firma
Task<JsonObject> RewriteAsync(    IReadOnlyDictionary<string, object?> body,    string? apiKey = null,    CancellationToken cancellationToken = default)

Rewrites a subject or a body and returns different versions of it, as the rewrite menu of the composer does. action is shorten, lengthen, rephrase, formal, casual or custom, and custom needs instruction to say what to change, or the call is a 422 invalid_parameter on instruction. target is body, the default, or subject, and count asks for 1 to 5 versions, 3 by default.

Give threadId when the text is a reply, so the rewrite fits the conversation. That also needs threads:read. The versions never repeat the original and never add facts that are not in it.

Nothing is saved. Each call spends one of the workspace's AI actions.

Parámetros

textstringObligatorio

The subject or body to rewrite.

actionstringObligatorio

What to do: shorten, lengthen, rephrase, formal, casual or custom, also in OpenEmail\Constants\RewriteActions.

targetdictionary

body or subject, also in OpenEmail\Constants\RewriteTargets. Defaults to body.

instructionstring

What to change, up to 500 characters. Required with custom.

countint

How many versions, 1 to 5. Defaults to 3.

threadIdstring

The thread the text replies in, read as context.

apiKeystring?

Overrides the client's API key for this call only.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A JsonObject with object set to rewrite, target and variations, a list of strings.

Ejemplo

using OpenEmail.Constants; var rewrite = await client.Emails.RewriteAsync(new Body{    ["text"] = "Hey, just checking whether you had any chance to look at the thing I sent last week?",    ["action"] = RewriteActions.Formal,    ["count"] = 2,}); Console.WriteLine(rewrite.ToJsonString());

Notas

  • The SDK does not retry it, because a second call spends a second AI action.

  • Fewer versions than count can come back when two of them turned out the same.

También disponible en

API
POST /emails/rewrite
TypeScript
emails.rewrite()
Python
emails.rewrite()
Ruby
emails.rewrite
PHP
emails->rewrite
Go
Emails.Rewrite
Java
emails().rewrite
CLI
openemail emails rewrite

Emails.SuggestSubjectAsync

Suggest a subject line

Alcancesemails:send
Firma
Task<JsonObject> SuggestSubjectAsync(    IReadOnlyDictionary<string, object?> body,    string? apiKey = null,    CancellationToken cancellationToken = default)

Reads the body of an email and returns a short subject for it, under 100 characters, in the style of the mail this workspace has sent, as the subject button of the composer does.

Nothing is saved. Each call spends one of the workspace's AI actions.

Parámetros

messagestringObligatorio

The body of the email, as text or HTML.

apiKeystring?

Overrides the client's API key for this call only.

cancellationTokenCancellationToken

Cancels the request.

Devuelve

A JsonObject with object set to subject_suggestion and subject.

Ejemplo

var suggestion = await client.Emails.SuggestSubjectAsync(new Body{    ["message"] = "<p>The September invoice is attached. Payment is due by the 30th.</p>",}); Console.WriteLine($"Subject: {suggestion["subject"]}");

Notas

  • The SDK does not retry it, because a second call spends a second AI action.

También disponible en

API
POST /emails/subject
TypeScript
emails.suggestSubject()
Python
emails.suggest_subject()
Ruby
emails.suggest_subject
PHP
emails->suggestSubject
Go
Emails.SuggestSubject
Java
emails().suggestSubject
CLI
openemail emails suggest-subject