Skip to main content
skill CX Codex GP ChatGPT official · OpenAI

twilio-sendgrid-email-send — Codex skill: send email via SendGrid

A skill that shows the agent how to send mail through the SendGrid v3 Mail Send API: single sends, batch sends with templates, scheduled sends and attachments. Requires an SG-prefixed API key.

Install into Codex · Skills CLI (Vercel) All methods and platforms ↓
npx skills add openai/plugins --skill twilio-sendgrid-email-send -a codex
Open on GitHub

What twilio-sendgrid-email-send does

Everything goes through POST /v3/mail/send, and the skill ships working Python and Node.js snippets. Single sends, personalized batch sends with Handlebars dynamic templates (IDs start with d-), scheduled sends, base64 attachments, categories and custom args for analytics. Sandbox mode validates a request without delivering it and answers 200 OK instead of 202 Accepted.

The skill reads like a reference with code plus a list of hard limits. You can schedule at most 72 hours ahead, and cancellation only works when a batch ID was assigned before sending. send_at wants Unix seconds: JavaScript's Date.now() returns milliseconds, and that timestamp gets silently rejected. One call carries at most 1,000 recipients, attachments cap at 30MB.

Before any send, the agent is told to confirm recipients, subject and body with the user, because delivered email cannot be recalled. Skip this skill if you are on the Twilio Email API at comms.twilio.com — different product, different credentials. The common trap: a typo in a dynamic_template_data key throws no error, the variable just renders as an empty string. Worth testing templates before a real send.

What it helps with

  • send an order confirmation email from a backend service
  • run a personalized batch send across a recipient list
  • schedule a send for later and cancel it if needed
  • attach a PDF invoice to an outgoing email
  • validate a send request without delivering anything

Example prompts for the agent

  • Send an order confirmation email to [email protected] through SendGrid
  • Do a batch send with dynamic template d-xxxxxxxxxxxxxxxxxxxxxxxxxxxx for two recipients
  • Schedule this send an hour out and show me the batch_id so I can cancel it

How to install twilio-sendgrid-email-send

1Skills CLI (Vercel)

npx skills add openai/plugins --skill twilio-sendgrid-email-send -a codex

2Manually: put the files in place

.agents/skills/twilio-sendgrid-email-send/SKILL.md

For all projects use ~/.agents/skills/

Step by step, with commands for each platform: Codex skills: how to install, where they live, how to call them

Questions about twilio-sendgrid-email-send

How do I install twilio-sendgrid-email-send in Codex?

Run npx skills add openai/plugins --skill twilio-sendgrid-email-send -a codex. The skill then lives at .agents/skills/twilio-sendgrid-email-send/SKILL.md.

What does twilio-sendgrid-email-send do?

It covers sending email through the SendGrid v3 Mail Send API: single and batch sends, dynamic templates, scheduled sends with cancellation, attachments and sandbox mode. Examples come in Python and Node.js.

Does it work with the Twilio Email API?

No. It expects a SendGrid API key with the SG prefix, while the Twilio Email API at comms.twilio.com is a separate product with its own credentials.

Source text

SKILL.md · MIT
---
name: twilio-sendgrid-email-send
description: >
  Send transactional and bulk email via the SendGrid v3 Mail Send API.
  Covers single sends, personalized batch sends with dynamic templates,
  scheduled sends with cancellation, attachments, and sandbox mode for
  testing. Use this skill when the caller has a SendGrid API key (SG.-prefix).
  Do NOT use this skill if the caller is using the Twilio Email API
  (comms.twilio.com) — that is a separate product with different credentials.
---

## Overview

> **Agent safety:** Always confirm recipients, subject, and content with the user before sending. Email is irreversible once delivered. Never send email autonomously without explicit user approval — especially for batch sends to multiple recipients.

All email sending goes through `POST /v3/mail/send`. This endpoint returns `202 Accepted` (queued) — NOT `200 OK` (delivered). Delivery confirmation comes asynchronously via Event Webhook. See `twilio-sendgrid-webhooks`.

---

## Basic Send

**Python**
```python
import os, sendgrid
from sendgrid.helpers.mail import Mail

sg = sendgrid.SendGridAPIClient(os.environ["SENDGRID_API_KEY"])
message = Mail(
    from_email="[email protected]",
    to_emails="[email protected]",
    subject="Order Confirmation",
    html_content="<p>Your order #1234 is confirmed.</p>"
)
response = sg.send(message)
print(f"Status: {response.status_code}")  # 202 = queued
```

**Node.js**
```javascript
const sgMail = require("@sendgrid/mail");
sgMail.setApiKey(process.env.SENDGRID_API_KEY);

const [response] = await sgMail.send({
    to: "[email protected]",
    from: "[email protected]",
    subject: "Order Confirmation",
    html: "<p>Your order #1234 is confirmed.</p>",
});
console.log(`Status: ${response.statusCode}`); // 202 = queued
```

---

## Personalized Batch Send with Dynamic Templates

Dynamic templates use Handlebars syntax. Template IDs start with `d-`. Create templates in SendGrid Console > Email API > Dynamic Templates.

**Python**
```python
from sendgrid.helpers.mail import Mail, To

message = Mail(
    from_email="[email protected]",
    to_emails=[
        To("[email protected]", dynamic_template_data={"name": "Alice", "order_id": "123"}),
        To("[email protected]", dynamic_template_data={"name": "Bob", "order_id": "456"}),
    ],
)
message.template_id = "d-xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
sg.send(message)
```

**Node.js**
```javascript
await sgMail.send({
    from: { email: "[email protected]" },
    template_id: "d-xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    personalizations: [
        { to: [{ email: "[email protected]" }], dynamic_template_data: { name: "Alice", order_id: "123" } },
        { to: [{ email: "[email protected]" }], dynamic_template_data: { name: "Bob", order_id: "456" } },
    ],
});
```

**Recipients in the same `to` array within a single personalization can see each other.** For private sends, use separate personalizations (one per recipient).

---

## Scheduled Sends

Schedule up to 72 hours in advance. Cancellation requires a batch ID assigned *before* sending.

**Python**
```python
import time, requests

headers = {"Authorization": f"Bearer {os.environ['SENDGRID_API_KEY']}", "Content-Type": "application/json"}

# Get batch ID first
batch = requests.post("https://api.sendgrid.com/v3/mail/batch", headers=headers).json()

# Include batch_id and send_at in the message
send_at = int(time.time()) + 3600  # Unix SECONDS, not ms

# Cancel if needed (before send_at)
requests.post("https://api.sendgrid.com/v3/user/scheduled_sends",
    headers=headers,
    json={"batch_id": batch["batch_id"], "status": "cancel"})
```

---

## Attachments

Base64-encode files in the `attachments` array. Total limit: 30MB per request (~22MB before encoding overhead).

```python
import base64
from sendgrid.helpers.mail import Mail, Attachment, FileContent, FileName, FileType, Disposition

with open("invoice.pdf", "rb") as f:
    encoded = base64.b64encode(f.read()).decode()

message = Mail(from_email="[email protected]", to_emails="[email protected]",
               subject="Your Invoice", html_content="<p>Invoice attached.</p>")
message.attachment = Attachment(FileContent(encoded), FileName("invoice.pdf"),
                                FileType("application/pdf"), Disposition("attachment"))
sg.send(message)
```

---

## Categories and Custom Args

**Categories** tag sends for analytics segmentation (up to 10 per message):
```python
message.category = ["transactional", "order-confirmation"]
```

**Custom Args** pass metadata through to Event Webhooks (key-value strings only):
```python
message.custom_args = {"order_id": "1234", "env": "production"}
```

These appear in webhook event payloads, enabling you to correlate delivery events back to your application data.

---

## Sandbox Mode (Testing)

Validates the request without delivering. Returns `200 OK` (not `202`).

```python
message.mail_settings = {"sandbox_mode": {"enable": True}}
response = sg.send(message)  # 200 = validated, not sent
```

---

## CANNOT

- **Cannot send more than 1,000 recipients per API call** — Hard limit. Split into multiple requests.
- **Cannot schedule sends more than 72 hours in advance** — `send_at` rejects timestamps beyond 72h.
- **Cannot cancel a send after processing** — Only scheduled messages with a pre-assigned batch ID can be cancelled.
- **Cannot use `send_at` with milliseconds** — JS `Date.now()` returns ms. Divide by 1000 or the timestamp is silently rejected (>72h).
- **The `subject` field in personalizations is a plain string override** — To use dynamic subjects, set Handlebars variables (e.g., `{{{subject}}}`) in the Dynamic Template's subject field and pass values via `dynamic_template_data`. The personalizations `subject` key bypasses the template subject entirely.
- **Undefined template variables render as empty strings** — No error for typos in `dynamic_template_data` keys. Silent failures.
- **`413 Payload Too Large` returns nginx HTML, not JSON** — Exceeding 30MB returns HTML error page. Check Content-Type before parsing.
- **Empty `content` when using `template_id`** — Omit the `content` field. If you include both, `template_id` takes precedence and `content` is ignored.

> **Agent usage:** When sending email on behalf of a user, always report back what was sent — recipients, subject, and the API response status code. Maintain an application-level audit log for all sends.

---

## Next Steps

- **Account setup and domain auth:** `twilio-sendgrid-account-setup`
- **Templates and settings:** `twilio-sendgrid-email-settings`
- **Delivery tracking via webhooks:** `twilio-sendgrid-webhooks`
- **Manage bounces and unsubscribes:** `twilio-sendgrid-suppressions`

© Twilio · MIT · openai/plugins

Similar skills

Everything for Backend and APIs →

From the same set304

The whole set →
twilio-voice-twiml A skill for building voice call logic with TwiML: Say, Play, Gather, Dial, Record and Conference verbs, plus a full inbound IVR example. CX Codex GP ChatGPT ★ 7,596repo stars twilio-verify-send-otp A skill that walks your agent through the full OTP lifecycle in Twilio Verify: create a service, send a code, check the submitted one. CX Codex GP ChatGPT ★ 7,596repo stars twilio-isv-sms-best-practices A skill for teams embedding SMS into a SaaS platform where customers message their own end users. Covers A2P 10DLC and toll-free onboarding, subaccounts and billing. CX Codex GP ChatGPT ★ 7,596repo stars twilio-sendgrid-inbound-parse A skill that walks your agent through SendGrid Inbound Parse: MX records, parsed vs raw mode, attachments and the usual pitfalls. CX Codex GP ChatGPT ★ 7,596repo stars twilio-security-api-auth Walks you through Twilio's four auth methods and helps you wire up the right one before shipping API calls to production. CX Codex GP ChatGPT ★ 7,596repo stars twilio-rcs-messaging A Claude and Claude skill that walks you from RCS sender onboarding to sending rich cards and carousels through Twilio. CX Codex GP ChatGPT ★ 7,596repo stars twilio-notifications-alerts-advisor Walks you through channel choice, urgency, delivery confirmation and fallback chains for transactional messages. CX Codex GP ChatGPT ★ 7,596repo stars twilio-lookup-phone-intelligence A Claude and Claude skill that validates phone numbers through Twilio Lookup v2 and scores fraud risk before you send an SMS or place a call. CX Codex GP ChatGPT ★ 7,596repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor