send_message
Send an email (Gmail) or a Slack message from one of the user's connected accounts. Gmail: to reply into a thread pass reply_to_external_id (external_id from a search result) — the reply is REPLY ALL by default (original sender + everyone on the original To and Cc, minus only the sending account — the user's other connected accounts are kept like any participant) and is sent FROM THE ACCOUNT THAT RECEIVED THE THREAD, so omit account for replies; subject and threading are derived too. A to you pass replaces the To line but the original recipients stay on Cc, and a cc you pass is added, never a replacement — recipients are only reduced with reply_mode='sender_only', which you should use only when the user explicitly asks to reply to the sender alone. Naming an account that did not receive the thread is refused unless allow_different_sender=true (only on the user's explicit request). The result reports the actual from / to / cc — tell the user who it went to. For a new mail pass to (address) and subject. Slack: set connector='slack', account=workspace label, to=channel ('#name' or channel id) or 'me' (DM to self); no subject. To reply to a Slack search hit, pass its external_id ('channel_id:ts') as reply_to_external_id — the channel is derived and the reply threads under that message; note the BOT posts, so a message can be searchable before it's replyable — a PUBLIC channel works even without the bot being a member (reconnect if the workspace predates chat:write.public), but a PRIVATE channel always needs the bot invited (/invite) regardless. File attachments (Gmail and Slack): pass attachment_ids (upload_id values staged via upload_attachment) and/or attachment_urls (public http(s) URLs fetched at send time). On Slack the body and the files become ONE post (uploaded as the connecting person when the workspace has the user-token files:write, otherwise as the app); a workspace connected before 2026-08-26 lacks files:write and returns a reconnect hint for attachments only — text-only sends there keep working. The user may have several Gmail accounts or Slack workspaces connected — pass account to pick one (call list_accounts first when unsure). This actually sends — confirm the recipient and body with the user before calling. Gmail needs the send scope (reconnect on a permission error); Slack channel-by-name needs channels:read (use a channel id or reconnect otherwise).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| cc | No | Gmail Cc recipient(s). On a reply these are ADDED to the original Cc — never a replacement. | |
| to | No | Gmail: recipient address (omit to reply). Slack: '#channel' / channel id / 'me' (DM to self). | |
| body | Yes | Plain-text message body. | |
| account | No | Account/workspace label to send from (see list_accounts). Omit when the user has exactly one for the connector. | |
| subject | No | Gmail subject (omit to reply, 元件名に Re: を付ける). Ignored for Slack. | |
| connector | Yes | Connector to send from ('gmail' or 'slack'). | |
| reply_mode | No | Gmail replies only. 'all' (default) = Reply All: original sender + original To and Cc, minus the sending account. 'sender_only' = add nobody automatically: To = your `to` (else the original sender), Cc = only your `cc`. Use 'sender_only' ONLY when the user explicitly asks to reply to the sender alone. | |
| attachment_ids | No | Gmail and Slack: upload_id values from upload_attachment to attach (staged uploads expire after 24h). Slack posts the body and the files as ONE message; a workspace connected before 2026-08-26 must be reconnected first (files:write). | |
| attachment_urls | No | Gmail and Slack: public http(s) URLs to fetch and attach at send time (15s timeout, 20MB total; private/localhost addresses are refused). | |
| reply_to_external_id | No | Gmail: thread external_id to reply into (from a search result). Slack: a search hit's external_id ('channel_id:ts') to reply in-thread (channel derived), or a bare ts (then `to` is required). | |
| allow_different_sender | No | Gmail replies only. A reply is sent from the account that RECEIVED the thread; if `account` names a different one the send is refused (reply_account_mismatch). Set true only when the user explicitly wants to answer from that other account. |