Skip to the documentation
Ruby

Drafts

`drafts.list`, `list_all`, `iterate`, `get`, `create`, `update` and `delete`.

Every method

drafts.rb
page = client.drafts.list(query: "invoice", limit: 25)draft = client.drafts.get("draft-5f0c2a9e-8b1d-4e7a-a3c6-2d9f41b7e0c8")puts page.items.size, draft[:subject] created = client.drafts.create(  to: ["[email protected]"],  cc: [],  bcc: [],  subject: "Your September invoice",  html: "<p>Draft body.</p>",  from: "[email protected]",  threadId: "CAHk7pQ2x9LmZ4-mail.example.com") updated = client.drafts.update(created[:id], subject: "Revised")client.drafts.delete(updated[:id])

update keeps the draft’s id, so the value it answers with is always the one you passed. An unknown id is a 404, raised as OpenEmail::NotFoundError, rather than a new draft.

The fields of a draft are keyword arguments under the API’s names, so the thread a draft replies to is threadId:. They can also be passed as one Hash. A draft comes back as a Hash with Symbol keys, so draft[:subject] reads the subject. Every write answers with only object and id, so read the whole draft with get.

list pages the way threads.list does. The API’s pageToken comes back as next_cursor and goes in as cursor:, and list_all and iterate follow it for you. iterate yields each draft to a block, or returns an Enumerator without one. A page holds 25 drafts unless limit: asks for up to 100. query: takes the search syntax of threads.list, and the search never leaves the drafts. A row is only object and id, so call get for the recipients, subject and body.

The drafts list states no hasMore, so has_more? is true whenever a cursor came back. The server offers one whenever a page is full, so a last page that happens to be full is followed by one empty page.

A draft is stored as a thread labelled DRAFT, which is why client.threads.list(folder: "draft") lists the same drafts. get, update and delete answer an ordinary thread id with a 404, even though threads.get opens it. delete removes a draft for good. It does not go to the Bin and there is no undo.

To send a draft, pass its id to emails.send as draftId:. The draft supplies the content and the send supplies the envelope. A draft cannot be combined with template or translate.

send_draft.rb
client.emails.send(  from: "[email protected]",  to: "[email protected]",  draftId: "draft-5f0c2a9e-8b1d-4e7a-a3c6-2d9f41b7e0c8")

Parameters: drafts.create and drafts.update

toArray<String>
Recipient addresses as an Array of Strings, not the Hash forms `emails.send` accepts, because this endpoint joins the Array into the comma-separated list the driver wants. A String may carry a display name, as in `Ada Lovelace <[email protected]>`, but a name that contains a comma splits into two broken recipients. Unlike `emails.send`, the gem does not wrap a lone String in an Array here, so pass `["[email protected]"]`. On create an omitted Array saves as empty. On update an omitted field leaves the stored recipients alone, since the handler reads the draft first and merges.
ccArray<String>
Cc addresses, in the same form as `to`. Empty on create when omitted, and untouched on update when omitted.
bccArray<String>
Bcc addresses, in the same form as `to`. Empty on create when omitted, and untouched on update when omitted.
subjectString
The draft’s subject, at most 998 characters, the RFC 5322 line limit. On create it defaults to an empty String, and an empty subject is stored as `(no subject)`, so a draft always has one.
htmlString
The draft body as markup, at most 1,000,000 characters. It is the body that wins. `html` and `text` feed the driver’s single message field, so sending both stores this one.
textString
A plain-text body, at most 1,000,000 characters, used only when `html` is absent. The draft stores one body rather than two parts, so text supplied here comes back unconverted on `html` when the draft is read.
fromString
The sender address to save on the draft, with or without a display name. Left out on create, the draft has no sender. On update it is carried through from the stored draft when omitted. The driver rebuilds the whole message from what it is handed, so a partial patch that dropped it would silently change the chosen sender. An empty String or nil on update clears it.
threadIdString
Attach the draft to an existing thread so it saves as a reply. Like `from`, it is carried through on update when omitted, because rebuilding the message without it would detach the reply from its thread. An empty String on update detaches it. The draft is still stored as a thread of its own under its own id, so it is listed with the drafts rather than inside the thread it replies to.

Leave a field out to keep it. Passing nil is not the same. The gem sends it, and every field refuses it with a 422 invalid_parameter except from on update, where nil clears the sender. Call compact on a Hash of optional values before you pass it. The body is strict as well. A field outside these eight is refused the same way, and there is no field for attachments.

Response: a draft (drafts.get)

objectString
Always `draft`.
idString
The draft’s id, `draft-` followed by a UUID. Writes answer with only `object` and `id` rather than a whole draft, so read the id off the result instead of reusing the one you sent.
toArray<String>
The recipient addresses as the draft stored them, bare, with any display name dropped. An empty Array, never nil, when the draft has none.
ccArray<String>
Cc addresses as stored. An empty Array, never nil, when the draft has none.
bccArray<String>
Bcc addresses as stored. An empty Array, never nil, when the draft has none.
subjectString
The stored subject, never nil. A draft saved without one reads `(no subject)`, the placeholder the mailbox stores, so compare with that rather than checking for an empty String.
htmlString
The stored body, or an empty String where the draft has none. There is no separate text field on the way out, so a draft saved with `text` alone is returned here.
fromString or nil
The address the draft was saved with, reported only while the workspace can still send as it. It is nil for a draft saved without a sender or from an address that has since gone.
threadIdString or nil
The thread the draft replies to, or nil for a draft that starts a new conversation.
attachmentsArray<Hash>
Each entry has only `filename` and `contentType`, because draft attachments are stored as names and types without content. An `update` empties this list.