Leo LogoHelloLeo
IntegrationsTemplatesPricingCommunity
Book a demoSign InGet Started
Leo LogoHelloLeo

The AI developer that builds the apps your ERP doesn't have — internal tools, portals and dashboards, running in production on top of NetSuite, Odoo, Salesforce and more.

Applications

  • HelloLeo for NetSuite
  • HelloLeo for Odoo
  • HR & Employees
  • Inventory
  • Accounting & Procurement

Integrations

  • Shopify integration
  • HubSpot integration
  • WhatsApp Business integration
  • Salesforce integration
  • Stripe integration
  • Google Sheets integration
  • Outlook integration
  • QuickBooks integration
  • All integrations

Product

  • Pricing
  • Templates
  • vs AI coding tools

Company

  • Contact

Resources

  • Documentation
  • Help Center
  • Community

Legal

  • Trust Center
  • Security
  • Status
  • Privacy Policy
  • Terms of Service
  • DPA
Gmail logo
Integration

Connect Gmail to your ERP

Gmail offers private and secure email by Google at no cost, for business and consumer accounts.

Communication
Browse all integrations

What Leo can do with Gmail

21 actions Leo can use in the apps and agents it builds for you: 9 that read Gmail data, 12 that create or update it.

reads data writes data deletes data

Read from Gmail · 9

  • Get Thread

    Fetch an entire Gmail thread (conversation) by thread ID — returns every message in order with headers, decoded body text, and attachment metadata. Use this after Find Emails when the user wants the full conversation rather than a single message. Each result from Find Emails includes a threadId you can pass here. With format: full (default) each message includes decoded text/html bodies and attachment metadata. Use format: metadata to skip bodies and get only headers + labelIds — useful for large threads. Responses are capped — oversized threads fall back to metadata-level detail (or are further truncated from the tail) with a [truncated] marker so the caller knows to narrow the request.

    Docs ↗
  • List Labels

    List every label in the authenticated user's mailbox (system labels like INBOX, SENT, TRASH, STARRED, UNREAD and user-created labels). Call this before Modify Labels or Find Emails when you need to target a label that the user named rather than an obvious system label — it resolves a name like Clients/Acme to its opaque label ID. User labels are returned first, then system labels.

    Docs ↗
  • Get Current User

    Returns the authenticated Gmail user's name, email address, and mailbox stats (total messages and threads). Call this first when the user says 'my emails', 'my inbox', or needs identity context. Use the returned emailAddress to identify the user's own messages in Find Emails results.

    Docs ↗
  • Find Emails

    Search the user's Gmail mailbox with Gmail's native query syntax and return matching messages (headers + snippet by default; full bodies when requested). Use this tool for every "find", "search", "list my", or "show me" email intent. The q parameter accepts the full Gmail search operator set — combine operators freely: from:[email protected] is:unread newer_than:7d has:attachment subject:"DNA sequences". Common operators: from:, to:, subject:, has:attachment, filename:pdf, is:unread, is:starred, label:INBOX, newer_than:7d, older_than:1m, after:2025/01/01, before:2025/12/31, category:primary. labelIds accepts either raw label IDs (INBOX, STARRED) or user-visible names (Clients/Acme) — names are resolved server-side via List Labels. Each returned message carries id, threadId, labelIds, the decoded subject/sender/recipient/date, and a snippet. With format: "full" the decoded body text and payload.parts[].body.attachmentId + filename + mimeType are also included — feed those into Download Attachment, or feed threadId into Get Thread for the whole conversation. Set `fields` on every call to name just what you need — message records are large, and a wide search returns tens of thousands of characters that crowd out the rest of the task. id and threadId are always returned. To BROWSE or COUNT, use ["subject", "sender", "date"]. To READ or SUMMARISE — "catch me up", "what did X say about Y", "is there anything I need to reply to" — use `["subject", "sender", "date", "bodyText"]`. bodyText is the decoded plain-text body (HTML converted, MIME scaffolding and attachments stripped), about half the size of the raw payload, and requesting it fetches full messages for you. Never answer a question about what an email SAYS from `snippet` — it is a fixed ~200-character prefix, so the sentence you need is usually past its end, and nothing in a snippet indicates that it was cut. Where the snippet is all you asked for and content was likely cut, the message carries snippetTruncated: true. format stays metadata unless you need the raw MIME tree for Download Attachment, in which case pass format: "full" and request payload. Responses are capped. Over the cap: if you named fields, whole messages are dropped rather than your chosen fields being removed, and the note says how many of how many are shown — narrow q and retry. If you named none, messages are compacted instead so counts stay accurate. bodyText shrinks toward a floor before anything is dropped, flagging each cut message with bodyTruncated: true. See the documentation and Gmail search operators.

  • Download Attachment

    Download a Gmail message attachment to /tmp and return its path + metadata. File Stash syncs the file and exposes a presigned download URL so the caller can retrieve it. Call Find Emails (with format: "full") or Get Thread first — attachment IDs only appear in full-format message reads; each returned message's payload.parts[] enumerates attachments as { body.attachmentId, filename, mimeType }. Pass the enclosing message's id as messageId and the part's body.attachmentId as attachmentId. If filename is omitted, the action looks up the attachment's filename from the message payload. Set convertToPdf: true to convert image / HTML / plain-text / DOCX attachments to PDF during download; other MIME types are rejected.

    Docs ↗
  • List Signature Options

    Retrieves available options for the Signature field.

  • List Send As Aliases

    List all send as aliases for the authenticated user.

    Docs ↗
  • List Send as a Delegate Options

    Retrieves available options for the Send as a Delegate field.

  • Get Send As Alias

    Get a send as alias for the authenticated user.

    Docs ↗

Write to Gmail · 12

  • Send Email

    Send a new email OR reply to an existing thread from the authenticated Gmail account. For a fresh message, set to/subject/body; leave inReplyToMessageId blank. To reply to a thread, pass the id of any message in that thread as inReplyToMessageId — the tool preserves threading (References, In-Reply-To, threadId) and auto-prefixes Re: on the subject. Use Find Emails or Get Thread to locate the message ID. Set replyAll: true to fan-out to the original From/To/Cc (minus the user's own address); otherwise only the original sender is addressed. bodyType controls whether body is treated as plain text (default) or HTML. To send to yourself, pass "me" in to — the action resolves it to the authenticated user's email address. No pre-call to Get Current User required. Attachments: for small inline content (the common case in MCP / cloud runs), set attachmentContent to the file's text contents and attachmentFilename to its name. For files already on disk (Pipedream workflows, File Stash), use attachments[] + attachmentFilenames[] instead.

    Docs ↗
  • Modify Labels

    Add and/or remove labels on one or more Gmail messages in a single call. In Gmail, most inbox-state operations are label mutations under the hood, so this one tool covers archive / trash / untrash / star / unstar / mark-read / mark-unread / apply-label / remove-label. Use this whenever the user asks you to star, unstar, flag, archive, file, sort, label, tag, categorise, move, trash, delete, restore, or mark mail as read or unread — there is no separate tool for any of those. Pair it with Find Emails to turn a description of the mail ("the invoice from billing", "everything from last week") into the messageIds this tool needs. Apply it even when some messages already carry the target state: the operation is idempotent, and the user asked for an outcome, not a diff. Do NOT use this to set up filters, rules, or any automation that applies to mail that has not arrived yet. This tool labels messages that already exist, one batch at a time. Gmail filters, auto-forwarding, and the vacation responder are settings-level features with no action in this set — if the user asks to "automatically label incoming mail", "skip the inbox from now on", or "set up a rule", say so outright rather than gathering criteria you cannot act on, and point them at Gmail's own settings. ⚠️ Trashing is destructive — confirm before you do it. Adding TRASH removes mail from the mailbox, and nothing in this tool set can permanently delete or restore in bulk beyond untrashing. When the request would trash mail the user did not enumerate individually ("trash everything from X", "clear out this label", "delete the old ones"), first say how many messages match and what they are, and get explicit confirmation. Every other operation here is safely reversible and needs no confirmation. Common recipes (pass these in addLabels / removeLabels): - Archive → removeLabels: ["INBOX"] - Move to trash → addLabels: ["TRASH"] - Untrash (restore) → removeLabels: ["TRASH"], addLabels: ["INBOX"] - Star → addLabels: ["STARRED"] - Unstar → removeLabels: ["STARRED"] - Mark read → removeLabels: ["UNREAD"] - Mark unread → addLabels: ["UNREAD"] - Apply a user label → addLabels: ["Clients/Acme"] (pass the name or the label ID) - Apply user label AND archive → addLabels: ["Clients/Acme"], removeLabels: ["INBOX"] addLabels and removeLabels accept either raw label IDs (system labels like INBOX, STARRED, UNREAD, TRASH) or user-visible label names — names are resolved via List Labels before the API call. Use Create Label first if you need to apply a brand-new label that doesn't yet exist.

    Docs ↗
  • Create Label

    Create a new user label in the authenticated Gmail mailbox and return its ID. Call this before Modify Labels whenever the label the user wants to apply doesn't yet exist — List Labels will tell you what's already there. Idempotent: if a label with the same name already exists, the action swallows the 409, looks it up by name, and returns the existing label with alreadyExisted: true so the caller can proceed. Nested labels are expressed with / — e.g. Clients/Acme creates or targets a sub-label under Clients. color is optional; when provided, both textColor and backgroundColor must be supplied together and must come from Gmail's fixed palette.

    Docs ↗
  • Create Draft

    Create an unsent draft in the authenticated Gmail account. Same parameter shape as Send Email — the difference is the message is saved to Drafts instead of being sent. For a reply-draft, pass inReplyToMessageId (from Find Emails / Get Thread); the subject, References, In-Reply-To, and threadId are derived from the referenced message. bodyType controls whether body is treated as plain text (default) or HTML. To draft to yourself, pass "me" in to — the action resolves it to the authenticated user's email address. No pre-call to Get Current User required. Attachments use file-ref inputs and require matching attachmentFilenames[] entries.

    Docs ↗
  • Update Signature for Primary Email Address

    Update the signature for the primary email address.

    Docs ↗
  • Update Signature for Email in Organization

    Update the signature for a specific email address in an organization. A Google Cloud service account with delegated domain-wide authority is required for this action.

    Docs ↗
  • Delete Label

    Immediately and permanently delete a user-created label from the authenticated Gmail mailbox, removing it from every message and thread it was applied to. Only user-created labels can be deleted — Gmail's built-in system labels (INBOX, SENT, SPAM, TRASH, etc.) cannot. This deletes the label *definition* itself; to merely detach a label from specific messages without removing it, use Modify Labels with removeLabels instead.

    Docs ↗
  • Bulk Archive Emails

    Archive multiple emails at once.

    Docs ↗
  • Remove Label from Email

    Remove label(s) from an email message. See the docs

  • Delete Email

    Moves the specified message to the trash.

    Docs ↗
  • Archive Email

    Archive an email message.

    Docs ↗
  • Add Label to Email

    Add label(s) to an email message. See the docs

Pair Gmail with your ERP

Leo connects Gmail to the ERP your business already runs on: the records it reads in Gmail land in your ERP, and what changes in the ERP flows back.

Odoo logo
Gmail + Odoo
See Odoo →
NetSuite logo
Gmail + NetSuite
See NetSuite →

How it works

  1. 01
    Connect Gmail

    Authorize Gmail once, in a couple of clicks. Leo only gets the permissions you grant.

  2. 02
    Describe what you need

    In plain language: the dashboard, portal or agent you want across Gmail and your ERP. No code, no mapping spreadsheets.

  3. 03
    Run it

    Leo builds it, you review, it goes live. Agents run on a schedule or on events, under the guardrails you set.

Gmail integration: questions

What can Leo do in Gmail?
Leo has 21 Gmail actions available: 9 read data and 12 create or update it. Any of them can be combined with your ERP data in an app or an agent.
Which ERPs does the Gmail integration work with?
Odoo and NetSuite today, through connectors we build and maintain ourselves. Gmail connects through our connector network, so the same app or agent can use both sides.
Is my data safe?
You authorize Gmail yourself and choose the permissions. Leo acts within them, every action is logged, and you can revoke the connection at any time.

More communication integrations

  • Microsoft Teams logoMicrosoft Teams
  • Twilio logoTwilio
  • Discord logoDiscord
  • Bot for Slack logoBot for Slack
  • WhatsApp Business logoWhatsApp Business
  • Telegram logoTelegram
  • Microsoft Outlook Email logoMicrosoft Outlook Email