# Find Emails — Gmail

> 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…

- Key: `gmail-find-email`
- Type: Action (Read-only)
- Version: 0.3.1
- App: Gmail (`gmail`) — https://pipedream.com/apps/gmail.md
- This page (HTML): https://pipedream.com/apps/gmail/actions/find-email
- Hints: read-only · open-world
- Source: https://github.com/PipedreamHQ/pipedream/blob/master/components/gmail/actions/find-email/find-email.mjs

## Description

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:alan@ingen.com 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](https://developers.google.com/gmail/api/reference/rest/v1/users.messages/list) and [Gmail search operators](https://support.google.com/mail/answer/7190).

## Props

| Prop | Type | Required | Description |
|---|---|---|---|
| `q` | `string` | No | Gmail search query using standard search operators. Examples: is:unread newer_than:7d, from:noreply@github.com has:attachment, subject:"Eval-Thread-Test", label:INBOX is:starred. Leave blank to return the most recent messages across the mailbox. |
| `labelIds` | `string[]` | No | Only return messages that carry all of these labels. Accepts either raw label IDs (e.g. INBOX, STARRED, UNREAD, TRASH, SPAM) or user-visible label names (e.g. Clients/Acme) — names are resolved against List Labels before the request is sent. |
| `includeSpamTrash` | `boolean` | No | Include messages from SPAM and TRASH in results. Defaults to false. |
| `maxResults` | `integer` | No | Maximum number of messages to return. Default 25, Gmail API max 500. Lower this for large/busy inboxes to keep responses under the token cap. |
| `format` | `string` | No | metadata (default) — headers + snippet only, much smaller responses. Use this for every "find", "count", "which" query. full — includes decoded body text and attachment IDs. Use only when you need to read message contents or download an attachment. |
| `fields` | `string[]` | No | Return only these fields on each message, instead of the full record. Always set this unless you genuinely need every field — message records are large, and a wide search can return tens of thousands of characters that crowd out the rest of the task. id and threadId are always included so results can be fed into Get Thread, Modify Labels, or Download Attachment. Choose by what you are doing: Browsing, counting, "which emails…" → ["subject", "sender", "date"]. Add labelIds to check read/starred state. Reading, summarising, "catch me up", "what did X say" → ["subject", "sender", "date", "bodyText"]. bodyText is a derived field: the decoded plain-text body, HTML converted, attachments and MIME scaffolding stripped. It is roughly half the size of payload and is what you want for any question about what an email SAYS. Requesting it fetches full messages automatically — you do not also need format: "full". Downloading an attachment → ["payload"] with format: "full", then read payload.parts[].body.attachmentId. Do NOT try to answer a content question from snippet: it is a fixed ~200-character prefix, so the sentence you need is usually past its end, and a snippet gives no sign that anything was cut. Ask for bodyText instead. Omit fields entirely to return the complete message record, exactly as this tool has always done. |
| `bodyChars` | `integer` | No | Maximum characters of bodyText to return per message. Default 2000, which covers a normal one-page email in full. Only applies when bodyText is requested in fields. Any message whose body is cut comes back with bodyTruncated: true and bodyTotalChars (its real length) — re-fetch that single message with a higher limit, or use Get Thread, to read the rest. Raise it for long newsletters or threads; lower it to fit more messages in one response. |

## Run it

**MCP**

```ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
import { PipedreamClient } from "@pipedream/sdk"

const pd = new PipedreamClient({
  projectId: process.env.PIPEDREAM_PROJECT_ID!,
  clientId: process.env.PIPEDREAM_CLIENT_ID!,
  clientSecret: process.env.PIPEDREAM_CLIENT_SECRET!,
  projectEnvironment: "production",
})

const accessToken = await pd.rawAccessToken

const transport = new StreamableHTTPClientTransport(
  new URL("https://remote.mcp.pipedream.net/v3"),
  {
    requestInit: {
      headers: {
        Authorization: `Bearer ${accessToken}`,
        "x-pd-project-id": process.env.PIPEDREAM_PROJECT_ID!,
        "x-pd-environment": "production",
        "x-pd-external-user-id": "{external_user_id}", // any stable ID for this user in your system
        "x-pd-app-slug": "gmail",
      },
    },
  },
)

const mcp = new Client({ name: "my-agent", version: "1.0.0" })
await mcp.connect(transport)

const { tools } = await mcp.listTools()

// listTools() hands your model this tool's input schema, so it can
// fill the arguments itself:
const result = await mcp.callTool({
  name: "gmail-find-email",
  arguments: {
    q: "Search Query",
    labelIds: ["Label IDs or Names"],
  },
})
```

**TypeScript**

```ts
import { PipedreamClient } from "@pipedream/sdk"

const pd = new PipedreamClient({
  projectId: process.env.PIPEDREAM_PROJECT_ID!,
  clientId: process.env.PIPEDREAM_CLIENT_ID!,
  clientSecret: process.env.PIPEDREAM_CLIENT_SECRET!,
  projectEnvironment: "production",
})

const result = await pd.actions.run({
  id: "gmail-find-email",
  externalUserId: "{external_user_id}", // any stable ID for this user in your system
  configuredProps: {
    gmail: { authProvisionId: "apn_xxxxxxx" },
    q: "Search Query",
    labelIds: ["Label IDs or Names"],
  },
})

console.log(result)
```

**cURL**

```bash
curl -X POST https://api.pipedream.com/v1/connect/{project_id}/actions/run \
  -H "Content-Type: application/json" \
  -H "X-PD-Environment: production" \
  -H "Authorization: Bearer {access_token}" \
  -d '{
    "external_user_id": "{external_user_id}",
    "id": "gmail-find-email",
    "configured_props": {
      "gmail": { "authProvisionId": "apn_xxxxxxx" },
      "q": "Search Query",
      "labelIds": ["Label IDs or Names"]
    }
  }'
```

---

- App: https://pipedream.com/apps/gmail.md · All apps: https://pipedream.com/apps
