Loopfour
Integrations

Email actions

Reference for the Send Email, Gmail and Outlook actions: step types, connections, each action id, the fields each executor reads, outputs and an example.

Three blocks send email: Send Email (resend), Gmail (gmail) and Outlook (outlook). For the plain-language guide, see Email (Gmail, Outlook, Send Email).

BlockAction idsStep typeConnection
Send Emailresend.sendactionNone. The worker's Resend API key sends it
Gmailgmail.<operation>gmailGmail (Google OAuth)
Outlookoutlook.<operation>actionOutlook (Microsoft OAuth)

To start a workflow from an inbound email, use the email trigger; see Inbound email trigger. Gmail and Outlook have no trigger.

Send Email

resend.send is the block's only action. It needs no connection.

FieldStudio labelTypeNotes
toTostring or string[]Required
subjectSubjectstringRequired
bodyBodyobject{ "html": "..." }, { "text": "..." } or both. Required in practice
layoutEmail layoutbranded or nonebranded (default) wraps body.html in the Loopfour email template unless it is already a complete HTML document. body.text is not wrapped
cc, bccCC, BCCstring[]Must be arrays
reply_to–stringReply-to address
from–stringSender. Defaults to onboarding@resend.dev
attachments–array{ filename, content, content_type? }, content base64

The executor reads body.html and body.text only, so a plain string body sends no message text. A string cc or bcc fails the step, and the Studio field replyTo is not read; use reply_to. Studio saves the Body field as a string, so steps built in Studio send a subject with no body. The overdue invoice template writes body as an object and sets from.

Output: the Resend response, { "id": "..." }.

Gmail

Write Gmail steps as "type": "gmail" and put the operation in config.action, for example "action": "searchEmails". The top-level action (gmail.searchEmails) is what workflow validation checks. A "type": "action" step fails at run time for searchEmails, getEmail and replyToEmail, because the runtime maps those names to listMessages, getMessage and replyToThread only inside the Gmail step type.

Action idStudio labelWhat it does
gmail.sendEmailSend EmailSend an email.
gmail.searchEmailsSearch EmailsSearch the mailbox with Gmail search syntax.
gmail.getEmailGet EmailRead one email. With hashAttachments, return a SHA-256 for each attachment instead of the file.
gmail.createDraftCreate DraftCreate a draft.
gmail.replyToEmailReply to EmailReply in the email's thread.
gmail.forwardEmailForward EmailForward an email, with its attachments by default.
gmail.downloadAttachmentsDownload AttachmentsReturn an email's attachments as base64 content.
gmail.archiveEmailArchive EmailArchive a message by removing it from the Inbox without deleting it.
gmail.markReadMark as ReadMark a message as read by removing the UNREAD label.
gmail.markUnreadMark as UnreadMark a message as unread by adding the UNREAD label.
gmail.modifyLabelsAdd or Remove LabelsAdd or remove labels, creating missing ones by default.
gmail.listLabelsList LabelsList every system and user label in the mailbox, with its ID, name, and type.
gmail.createLabelCreate LabelCreate a label.
gmail.deleteLabelDelete LabelDelete a label.
FieldStudio labelTypeUsed byRequired for
connectionGmail Accountstring (connection id)AllOptional. Without it the step uses the company default connection for this system
toTostringsendEmail, createDraft, replyToEmail, forwardEmail
subjectSubjectstringsendEmail, createDraft
bodyBodystringsendEmail, createDraft, replyToEmail, forwardEmail
ccCCstringsendEmail, createDraft, forwardEmail
bccBCCstringsendEmail, createDraft, forwardEmail
searchQuerySearch QuerystringsearchEmails
messageIdMessage IDstringgetEmail, replyToEmail, forwardEmail, downloadAttachments, archiveEmail, markRead, markUnread, modifyLabels
includeAttachmentsInclude Original AttachmentsbooleanforwardEmail
includeInlineInclude Inline ImagesbooleandownloadAttachments
hashAttachmentsReturn Hashes Instead of AttachmentsbooleangetEmail
addLabelsAdd LabelsstringmodifyLabels
removeLabelsRemove LabelsstringmodifyLabels
createMissingLabelsCreate Missing LabelsbooleanmodifyLabels
labelNameLabel NamestringcreateLabel, deleteLabel
maxResultsMax ResultsnumbersearchEmails

Fields each action reads

  • searchQuery is passed to Gmail as q; either name works. maxResults and pageToken page the results.
  • cc and bcc accept an array or a comma-separated string.
  • sendEmail and createDraft need to, subject and body (plain text) or htmlBody. They also read from, replyTo and attachments.
  • replyToEmail needs threadId, to and body or htmlBody; messageId sets the In-Reply-To header. Studio has no threadId field, so a reply built only in Studio fails with threadId is required. Read threadId from a getEmail or searchEmails result.
  • forwardEmail needs messageId and to. body is a note above the forwarded email. Attachments are included by default (includeAttachments), up to 15 MiB in total.
  • downloadAttachments returns the attachments as base64, up to 3 MiB in total. includeInline adds inline images.
  • getEmail with hashAttachments: true returns the full message with an attachmentHashes list (sha256:<hex> per attachment) and the file data removed.
  • modifyLabels takes addLabels and removeLabels as label names or ids, and creates missing labels unless createMissingLabels is false.

Output

Each action returns the Gmail API response. searchEmails returns messages (each { id, threadId }), nextPageToken and resultSizeEstimate; read the content with getEmail.

Outlook

Write Outlook steps as "type": "action" with "action": "outlook.<operation>".

Action idStudio labelWhat it does
outlook.sendEmailSend EmailSend an email.
outlook.listMessagesSearch EmailsSearch or list messages.
outlook.getMessageGet EmailRead one email.
outlook.createDraftCreate DraftCreate a draft.
outlook.replyToThreadReply to EmailReply to an email.
FieldStudio labelTypeUsed byRequired for
connectionOutlook Accountstring (connection id)AllOptional. Without it the step uses the company default connection for this system
toTostringsendEmail, createDraft
subjectSubjectstringsendEmail, createDraft
bodyBodystringsendEmail, createDraft, replyToThread
ccCCstringsendEmail, createDraft
searchQuerySearch QuerystringlistMessages
messageIdMessage IDstringgetMessage, replyToThread
maxResultsMax ResultsnumberlistMessages

Fields each action reads

Some Outlook keys have a second name, and some have no Studio field:

ActionStudio fieldExecutor reads
listMessagessearchQuery, maxResultssearch or searchQuery (Graph $search), top or maxResults, filter (OData $filter), skip, orderBy, select, folderId
sendEmail, createDraftcccc and bcc as an array or a comma-separated string
replyToThreadNoneadditionalTo (an array or a comma-separated string); replyAll: true replies to all

When both names are set, search and top win over searchQuery and maxResults. top must be a positive whole number (a numeric string such as "5" works), and a value above 1,000 is sent as 1,000. skip must be a whole number of 0 or more. Any other value fails the step before Outlook is called. sendEmail and createDraft need to, subject and body (plain text) or htmlBody; sendEmail also reads replyTo, importance (low, normal, high) and attachments ({ name, contentBytes, contentType }).

Output

listMessages and getMessage return the Microsoft Graph response.

Legacy email step

Older workflows use "type": "email" with config.action set to send, send_template or schedule and config.provider set to gmail, outlook or resend (default gmail). The block is hidden from the Studio palette. It takes the same fields as Send Email above, with cc and bcc as arrays. New workflows should use the blocks above.

Example

Find this morning's vendor statement in the AP mailbox, read it, and email the team a short notice.

{
  "name": "Vendor statement notice",
  "trigger": { "type": "schedule", "cron": "0 8 * * 1-5", "timezone": "America/Los_Angeles" },
  "steps": [
    {
      "id": "find_statement",
      "type": "gmail",
      "name": "Find the statement",
      "action": "gmail.searchEmails",
      "config": {
        "action": "searchEmails",
        "searchQuery": "from:statements@vendor.example has:attachment newer_than:1d",
        "maxResults": 1
      }
    },
    {
      "id": "read_statement",
      "type": "gmail",
      "name": "Read the statement",
      "action": "gmail.getEmail",
      "config": {
        "action": "getEmail",
        "messageId": "{{steps.find_statement.messages.0.id}}"
      }
    },
    {
      "id": "notify_team",
      "type": "action",
      "name": "Tell the AP team",
      "action": "resend.send",
      "config": {
        "to": ["ap@yourcompany.example"],
        "subject": "Vendor statement received",
        "body": { "text": "A vendor statement arrived: {{steps.read_statement.snippet}}" },
        "from": "workflows@yourcompany.example"
      }
    }
  ]
}

Live catalog

  • GET /api/v1/blocks/resend, GET /api/v1/blocks/gmail and GET /api/v1/blocks/outlook return the actions and fields.
  • GET /api/v1/blocks/<type>/actions/<operation>/examples returns stored input and output examples where they exist.

Errors and limits

  • Gmail and Outlook fail the step with the provider's message, such as to is required or a Google or Microsoft API error.
  • Send Email fails with Resend API error (<status>): ... when Resend refuses the email, for example a from domain that is not verified.
  • Gmail declarative actions (archiveEmail, markRead, markUnread, listLabels) have a 30-second limit per call.

On this page