# Draft a reply to an inbound email

When a customer email lands in Salfio, have a Claude Code routine write the reply for you — straight into your Gmail Drafts folder.

Replying to client email is the kind of work that fills your day without obviously moving it forward. Most replies are short acknowledgements, answers to questions you've already discussed, or nudges back to an open thread.

This guide wires three pieces together so those replies write themselves:

- **Salfio** captures inbound email through your Gmail integration and links it to the right client.
- A **Salfio webhook** fires the `activity.email.created` event the moment the email is recorded.
- A **Claude Code remote routine** picks up the event, reads the thread and prior conversation history from Salfio, and drafts the reply directly in your Gmail — as a normal draft, ready for you to review and send.

End-to-end, your Gmail Drafts folder fills up with replies that already know the context.

## Prerequisites

- A Salfio organization with **Gmail** connected — see [Connect an integration](/docs/getting-started/connect-integration).
- A Claude Code account with **Routines** enabled and the **Salfio** and **Gmail** connectors authorized. The Salfio connector is the same MCP integration covered in [Connect from Claude.ai web](/docs/mcp/connect-claude-web) — once authorized for your Claude account, it's available to routines too.
- Access to **Settings → Webhooks** in the Salfio dashboard.

## 1. Create a Claude Code remote routine

A routine is a prompt that runs whenever its fire URL is POSTed to — Salfio will be the one POSTing.

In Claude Code, open **Routines** and click **+ New routine**. In the dialog:

1.  **Name** — anything you like, e.g. `Draft reply with Salfio context`.
2.  **Instructions** — paste the prompt below.
3.  **Select a trigger** — pick **API** ("Trigger from your own code by sending a POST request"). Salfio fires the routine through this trigger.
4.  **Connectors** — make sure at least **Salfio** and **Gmail** are in the list. Salfio lets the routine read client context and conversation history; Gmail lets it create the draft. Add whatever else helps (Google Drive, Linear, etc.).
5.  Click **Create**.

Claude Code will warn you that the routine can use **all** tools from the connectors — including writes — without asking for permission during runs. Keep the prompt strict about "draft, never send", and prune connectors you don't actually need.

### Routine prompt

Paste this into **Instructions**:

    You are an email-drafting assistant for the account owner. You are
    called once per inbound email and produce a Gmail draft (never send).

    The request body is `{"text": "<json string>"}` — run JSON.parse(text)
    to get the Salfio webhook envelope. The `activity` field describes the
    inbound email; `activity.clientId` identifies the Salfio client.

    Identify yourself first. The Gmail connector is authorized against one
    Google account — fetch its profile and treat that as "you" for this
    draft (your email, your name, your signature). If that address isn't
    on the inbound email's participant list, skip without drafting — this
    email wasn't addressed to you.

    Then use the Salfio connector to understand the relationship: pull
    the client, the AI-generated cards, and recent activities for that
    client. Pay particular attention to your own prior outbound messages
    to this client — they're the best model for the voice, signature, and
    level of formality you should match.

    If the email is internal, automated, or you can't find the client in
    Salfio, skip without drafting and say why.

    Then create a Gmail draft addressed to the other participants (not
    yourself) that reads like you wrote it: same language as the prior
    thread, same level of formality, directly addressing what the email
    actually asks. Reference relevant prior context naturally where it
    helps — don't quote it. End with a concrete next step or a specific
    question. Sign off with your first name. If you don't have enough
    information to answer, draft a short acknowledgement that buys time
    rather than fabricating.

    Reply back with the Salfio activity id, the Gmail draft id, and one
    sentence on what you decided to say.

### Grab the credentials

Right after you click **Create**, Claude Code shows the **API token** in a one-shot dialog (`sk-ant-oat01-…`). Copy it now — Claude won't show it again. Treat it like a password.

Then on the routine's detail page:

- Make sure **Status** is **Active**.
- Under **API**, click the copy icon next to **API trigger enabled** to copy the routine's **fire URL** (it looks like `https://api.anthropic.com/v1/claude_code/routines/<routine_id>/fire`).

You'll paste both into Salfio in the next step.

## 2. Register the routine as a Salfio webhook

Back in Salfio:

1.  Open **Settings → Webhooks**.
2.  Click **Add webhook** and fill in:
    - **Name** — something like `Email reply → Gmail draft`.
    - **Event** — `activity.email.created`.
    - **Transport** — `Claude routine`.
    - **URL** — paste the fire URL from step 1.
    - **Token** — paste the token from step 1.
3.  Save.

Salfio stores the token encrypted at rest and never shows it again. If you ever need to rotate it, generate a new one in Claude Code and edit the webhook here.

## 3. Send a test event

Don't wait for your next real email to find out something is wrong. Each webhook row has a **Send test event** button. Clicking it opens a small dialog with a single picker:

- **Synthetic sample (placeholder data)** — the default. Useful when you don't have a recent email yet, or when you want to exercise the routine without sending a real client conversation.
- **Any of your recent emails** — listed as `Client · "Subject" (relative time)`. Pick one to fire your routine against that exact payload.

Confirm the dialog. Within a few seconds:

- The webhook's **Last delivery** column updates with the delivery status. If you picked a real activity, a "View client" link appears on the success toast so you can jump to it.
- Claude fires the routine with the picked payload.
- A draft email appears in your Gmail **Drafts** folder, addressed to the participants from the payload.

If you don't see a draft, see [Troubleshooting](#troubleshooting) below.

## 4. Receive a real email

When a new email syncs from Gmail into Salfio:

1.  The email appears under **Activities** for the matching client.
2.  Salfio fires `activity.email.created` to your webhook.
3.  Claude reads the payload, pulls the client and recent history from Salfio, decides whether to act, and (if so) drafts the reply.
4.  You see the draft in your Gmail Drafts folder, addressed to the sender (and any external recipients already on the thread), with a reply that's aware of what's already been discussed.

Open the draft, edit anything you want, and send.

## What Salfio sends

Salfio's canonical webhook envelope carries the email on the `activity` field:

    {
      "event": "activity.email.created",
      "occurred_at": "2026-05-12T11:42:13Z",
      "organization": { "id": "9c1a…" },
      "activity": {
        "id": "8df8…",
        "clientId": "ad44…",
        "type": "email",
        "source": "gmail",
        "subject": "Quarterly review",
        "content": "Hi team — sharing the deck…",
        "occurredAt": "2026-05-12T11:42:13Z",
        "participants": ["[email protected]", "[email protected]"],
        "immutable": true,
        "archivedAt": null,
        "createdAt": "2026-05-12T11:42:14Z",
        "updatedAt": "2026-05-12T11:42:14Z"
      }
    }

Because Anthropic's routine `/fire` endpoint only accepts `{"text": "..."}`, Salfio wraps the envelope as a stringified JSON inside `text` before dispatching to a Claude routine. That's why the routine prompt above starts with `JSON.parse(text)` — once parsed, you get the exact structure shown above.

Full payload reference — including headers, retry behaviour, and the URL-endpoint transport — lives in [Webhooks](/docs/api/webhooks).

## Tips

**Skip the noise.** Newsletters, receipts, calendar invites, and no-reply senders are rarely worth a draft. The prompt above treats them as "automated"; if yours leak through, tighten the rule by checking the `From` address or common subject patterns explicitly in the prompt.

**Don't send from the routine.** Even if the Gmail connector lets the routine send, don't. Save as a draft and review. Auto-sending removes the review step that makes this workflow safe to run.

**Lean on the AI-generated cards.** The Salfio cards (briefing, topics, wins, risks) summarise the relationship state in a few sentences. Telling the routine to read them first usually produces tighter drafts than letting it page through a long activity list.

**Iterate on the prompt, not the wiring.** Once the webhook fires correctly, every quality improvement lives in the routine prompt. Rewriting "what counts as a real reply" is faster than touching any infrastructure.

## Troubleshooting

**The test event went green but no draft appeared.** The webhook fired successfully — the issue is on the routine side. Open the routine's run history in Claude Code and inspect the most recent run. Common causes: the routine has no Gmail connector, the Gmail connector is connected to a different Google account than you expected, or the routine decided "no follow-up needed" for the test payload.

**The webhook shows a non-`2xx` delivery.** Open the row in **Settings → Webhooks** and look at "Last delivery". A `401` means the token is wrong or has been revoked in Claude Code; a `404` means the routine was deleted; a `5xx` means Claude is having a bad moment — Salfio will retry on its standard curve.

**The draft replies in the wrong language.** The prompt tells Claude to match the language of the prior thread. If the inbound email is the very first message and the language is ambiguous, the routine may default to English. Add an explicit preference to the prompt for those cases.

**The draft ignores prior context.** The routine isn't reading enough history. Tighten the Salfio step in the prompt to require pulling recent activities before drafting, and consider raising the activity-history limit the routine asks for.

**Drafts go to the wrong Gmail account.** The Gmail connector inside your routine is connected to whichever Google account you authorized in Claude Code. Reconnect the connector against the account you want drafts to land in.

## Related

- [Draft a meeting recap email in Gmail](/docs/guides/draft-meeting-recap) — the sibling recipe for meetings.
- [Webhooks](/docs/api/webhooks) — full payload, headers, retry curve.
- [Connect an integration](/docs/getting-started/connect-integration) — Gmail and Fireflies setup.
- [Connect from Claude.ai web](/docs/mcp/connect-claude-web) — Salfio MCP authorization (same connector used in routines).

## Related pages

- [Administrator Tools](./administrator-tools.md)
- [Agent Tools](./mcp-external-servers.md)
- [Assign a Slack channel to a client over the API](./guides-assign-slack-channel.md)
- [Authenticated health check](./api-reference-gethealth.md)
- [Authentication](./api-authentication.md)
- [Cards](./cards.md)
- [Changelog](./changelog.md)
- [Changelog](../changelog.md)
- [Connect a workspace](./getting-started-connect-workspace.md)
- [Connect an integration](./getting-started-connect-integration.md)

# Agent Instructions

This portal answers questions programmatically. To receive a synthesized,
source-cited answer instead of crawling page by page, append the `?ask=`
query parameter to any page URL on this site:

    /guides/quickstart?ask=how+do+I+authenticate

Optional parameters:

- `&goal=<what-you-are-trying-to-do>` steers the answer toward your
  objective (e.g. `&goal=write+a+python+client`).
- `&version=<label>` scopes the answer to a mounted version when the
  portal publishes more than one.

The response is `text/markdown`: the answer followed by a `# Sources` list
of the portal pages it was grounded in. Status codes are the contract:

- `200` — the answer; `402` — the portal owner’s plan or answer credits are
  exhausted (surface this to your operator; do NOT retry); `429` — you are
  rate-limited; back off for the `Retry-After` seconds; `503` — the answer
  lane is temporarily unavailable; fall back to crawling the `.md` pages.

For the full corpus map read `llms.txt` at the site root; for the tool
surface (search + page fetch as MCP tools) see `/mcp`.
