SendGrid Send Email
Send email through SendGrid's v3 Mail Send API.
Purpose
This skill is for sending transactional email with SendGrid by calling POST /v3/mail/send directly.
Inputs:
fromverified sender email. This address should be a verified sender in your Twilio SendGrid account.- one or more
torecipients subject, unless the subject is defined by a dynamic templatetext,html, ortemplate_id- SendGrid API key from
--api-key,SENDGRID_API_KEY, or the locally saved key - automatic
custom_args.business_idfor application-side correlation, or user-provided--business-id
Output:
- dry-run JSON payload by default
- SendGrid HTTP status, message metadata, and one status-query prompt example when
--sendis explicitly provided
Sending email is irreversible once queued. Always confirm recipients, subject, and content with the user before running with --send.
What This Skill Needs
- user-provided sender. This address should be a verified sender in the user's Twilio SendGrid account.
- user-provided recipients and message content
- a SendGrid API key, usually
SENDGRID_API_KEY curlbashpython3
SendGrid API keys are separate from Twilio Account SID/Auth Token credentials. Do not use this skill for the separate Twilio Email API at comms.twilio.com.
API key resolution order:
--api-keyfor the current runSENDGRID_API_KEY- locally saved key at
~/.config/sendgrid-send-email/api_key
If no API key is available and the script is running interactively, prompt once and save it locally for future runs. If no API key is available in a non-interactive run, guide the user to read the SendGrid integration guide: https://frevana.gitbook.io/frevana-docs/email-integrations/sendgrid-integration.
Users can update the saved API key with:
bash <skill-path>/scripts/send_email.sh --api-key "SG..." --save-api-key
or clear it with:
bash <skill-path>/scripts/send_email.sh --clear-api-key
Execution Order
- Confirm the user explicitly wants to send email and has provided the final recipients, subject, and content.
- Prefer the bundled script over ad hoc
curlcommands. - Run a dry run first unless the user already asked for an immediate send and the final email details are unambiguous.
- Review the dry-run payload for recipient visibility, content, attachments, sandbox mode, and scheduled-send fields.
- Run again with
--sendonly after explicit user approval. - Treat HTTP
202as queued, not delivered. Delivery confirmation is asynchronous through SendGrid Email Logs, event webhooks, or thesendgrid-email-logskill. - Report the recipients, subject, business ID, sandbox/send mode, HTTP status, SendGrid
x-message-idheader, and a concise prompt example for querying status withsendgrid-email-logwhen available.
Commands
Dry-run a simple email
bash <skill-path>/scripts/send_email.sh \
--from "verified@example.com" \
--to "recipient@example.com" \
--subject "Hello" \
--text "Hello from SendGrid."
Actually send
bash <skill-path>/scripts/send_email.sh \
--from "verified@example.com" \
--to "recipient@example.com" \
--subject "Hello" \
--html "<p>Hello from SendGrid.</p>" \
--send
Multiple recipients with private personalizations
bash <skill-path>/scripts/send_email.sh \
--from "verified@example.com" \
--to "alice@example.com" \
--to "bob@example.com" \
--subject "Private update" \
--text "Each recipient is in a separate personalization." \
--private-recipients \
--send
Without --private-recipients, recipients in the same to array can see each other.
Dynamic template send
bash <skill-path>/scripts/send_email.sh \
--from "verified@example.com" \
--to "alice@example.com" \
--template-id "d-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
--dynamic-template-data-json '{"name":"Alice","order_id":"123"}' \
--send
When using --template-id, omit --text and --html unless the user specifically wants both. Template content normally comes from SendGrid.
Sandbox validation
bash <skill-path>/scripts/send_email.sh \
--from "verified@example.com" \
--to "recipient@example.com" \
--subject "Validate only" \
--text "This request is validated but not delivered." \
--sandbox \
--send
Sandbox mode validates the request without delivery and usually returns HTTP 200.
Attach a file
bash <skill-path>/scripts/send_email.sh \
--from "verified@example.com" \
--to "customer@example.com" \
--subject "Invoice" \
--html-file ./email.html \
--attachment ./invoice.pdf \
--send
Attachments are base64-encoded into the attachments array. Keep total request size under SendGrid's documented limit.
Add a business correlation ID
Every request automatically includes custom_args.business_id. To control the value, pass:
bash <skill-path>/scripts/send_email.sh \
--from "verified@example.com" \
--to "customer@example.com" \
--subject "Order update" \
--text "Your order shipped." \
--business-id "order_12345"
Use this ID later when correlating SendGrid Event Webhook events or application logs. Do not use it as the default Email Logs query path.
Fixed Request Shape
The script sends to:
- global region:
https://api.sendgrid.com/v3/mail/send - EU region:
https://api.eu.sendgrid.com/v3/mail/send
It sends JSON shaped like:
{
"personalizations": [
{
"to": [{ "email": "recipient@example.com" }],
"dynamic_template_data": { "name": "Alice" }
}
],
"from": { "email": "verified@example.com" },
"subject": "Hello",
"content": [{ "type": "text/plain", "value": "Hello from SendGrid." }],
"custom_args": {
"business_id": "sendgrid_email_20260615T120000Z_0123456789abcdef0123456789abcdef"
}
}
Optional fields are omitted when the user does not provide them. Require --from from the user. Do not invent sender identities, recipients, template IDs, categories, custom args, batch IDs, or scheduled-send timestamps.
Script Options
--from EMAILor--from "Name <email@example.com>"; required sender address. This address should be a verified sender in the user's Twilio SendGrid account.--to,--cc,--bcc; repeat flags or comma-separate values--subject--text,--text-file--html,--html-file--template-id--dynamic-template-data-json--reply-to--attachment PATH; repeatable--business-id VALUE; optional business correlation ID. Auto-generated when omitted and written tocustom_args.business_id--category NAME; repeatable, up to SendGrid's limit--custom-arg KEY=VALUE; repeatable--batch-id--send-at UNIX_SECONDS--sandbox--private-recipients--region global|eu--api-key KEYfor a one-time override--save-api-keyto save the--api-keyvalue for future runs--configure-api-keyto prompt for and save the key--clear-api-keyto remove the locally saved key--output PATHto save dry-run JSON or send metadata--sendto perform the API call
Notes
--sendis required for side effects; without it, the script only prints the payload.- Never echo or store the API key in user-visible output.
- The scripts can save the API key locally at
~/.config/sendgrid-send-email/api_keywith file permission600; do not print the key value back to the user. - Use
--api-key <key> --save-api-keyor--configure-api-keywhen the user wants to update the saved key. Use--clear-api-keywhen the user wants to remove it. - The
fromaddress should be a verified sender in the user's Twilio SendGrid account. - Every request includes
custom_args.business_id. Use--business-idto set a business-specific correlation ID; otherwise the script generates one. - Do not pass
--custom-arg business_id=...; use--business-idfor that reserved key. - Use
sendgrid-email-logfor Email Logs status queries, per-message event timelines, and opened/clicked checks. - After a successful send, the script returns
status_query.prompt_exampleandstatus_query.query_paramsso the user can ask the agent to query status later without displaying shell scripts. - If
--api-key,SENDGRID_API_KEY, and the locally saved key are all missing, tell the user to read https://frevana.gitbook.io/frevana-docs/email-integrations/sendgrid-integration to get the required configuration. - SendGrid returns
202 Acceptedfor queued mail. That does not mean delivered. - Sandbox mode returns validation status and does not deliver.
- For scheduled sends,
--send-atmust be Unix seconds, not JavaScript milliseconds. - For private bulk sends, use
--private-recipientsor separate API calls. - If a user shares an API key in chat, advise them to rotate it.
Example Prompts
中文
- "用 SendGrid 给 alice@example.com 发一封测试邮件"
- "用这个 verified sender 发送 HTML 邮件,先 dry run"
- "用 SendGrid template d-... 给这几个收件人分别发邮件"
English
- "Send a SendGrid email to this customer"
- "Dry-run this SendGrid Mail Send payload before sending"
- "Send a SendGrid dynamic template email with these variables"