Guide
Give an agent an email desk without Gmail OAuth
Connecting an agent to Gmail means an OAuth app, a consent screen, tokens that expire and refresh, and an agent that can send from your personal address. Plenty of builders end up keeping the agent read-only because of it. Deskhand takes the other route: the agent never holds a mailbox credential at all.
The setup
- Sign in and create an agent with the
draft_emailscope. Copy its key; it is shown once. - The agent drafts through the API or MCP with that key.
- By default the draft is approved on the spot and recorded as approved by the default policy. Turn approval on in Settings, or per agent, and drafts wait for you in Approvals instead.
Over HTTP a draft is written against a contact id, so upsert the contact first (it returns contact.id), then draft with that id. The MCP draft_email tool takes the email address directly.
curl -X POST https://deskhand.grain64.com/api/contacts/upsert \
-H "Authorization: Bearer $DESKHAND_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"ada@example.com","name":"Ada"}'
curl -X POST https://deskhand.grain64.com/api/emails/draft \
-H "Authorization: Bearer $DESKHAND_KEY" \
-H "Content-Type: application/json" \
-d '{"contact_id":"<id from the upsert response>","subject":"Following up","body":"Hi Ada, ..."}'
What happens to an approved draft
Approved mail to your own address, such as a test copy, is delivered by Deskhand. Approved mail to anyone else goes out through the To send queue, and the draft response and list_email_status report each message's state in a note. You copy each message or open it in your mail client, send it from there, and choose Mark sent. Deskhand records the send on the contact's timeline, moves the contact to contacted and tells the agent.
Guards that run on the server
- Contacts marked replied, unsubscribed or bounced cannot receive a new draft; the call refuses with the reason.
- A daily send cap per agent, one recipient per message and no attachments.
- An unsubscribe line and sender identity are added by the platform.
Replies
When a contact replies, the contact flips to replied, pending follow-ups for that contact are cancelled and the agent's next draft_email for them is refused with the reason. If inbound capture is off for your workspace, mark a contact replied in the console or with mark_replied.
What you give up
Mail is not sent from your own Gmail address by the agent. Today you send it yourself from the To send queue; the agent's part is the research and the writing, and yours is the send.
Try it
Free during early access: 3 agents, each with its own key, a pause switch and the full audit log. Start free
Related: Let an AI agent act on its own, and turn on approval only where you want it, A CRM for Claude Code agents: one command, one key per agent