SendGrid
SendGrid is a built-in Norq email provider. It builds requests for the
POST https://api.sendgrid.com/v3/mail/send endpoint (Web API v3).
Configuration
providers:
sendgrid:
config:
api_key: ${SENDGRID_API_KEY}
from: noreply@example.com
# Optional
from_name: "Acme" # SendGrid `from` becomes {email, name}
reply_to: support@acme.com # scalar OR list
# reply_to:
# - support@acme.com
routing:
email: sendgridapi_key and from are required. from_name and reply_to are optional.
Environment-variable fallback
If providers.sendgrid is not declared, Norq registers SendGrid when these
env vars are set:
| Var | Required |
|---|---|
NORQ_SENDGRID_API_KEY |
yes |
NORQ_SENDGRID_FROM_ADDRESS |
yes |
Capabilities
- Channels: email only.
- Batching: none at the public-API level. SendGrid’s
multi-recipient mechanism is the
personalizations[]array, which has different per-recipient personalization semantics than Resend’s/emails/batch. Norq reportsmax_batch_size = None, so the SDK iterates one message perprepare_sendcall. - Idempotency: best effort — there is no native dedup on the
SendGrid Web API. The caller-supplied (or auto-generated) idempotency
key is forwarded as
custom_args.idempotency_keyfor log correlation only. - Attachments: up to 30 MB total across a single request.
Inline images (
type: image/...+content_id+disposition: inline) are supported. reply_to: accepts scalar or list. SendGrid serialises the list form asreply_to_list[].- CLI: works. SendGrid uses Bearer auth and plain HTTP/1.1, so the
norqCLI binary can deliver email without any special dependencies.
Request shape
- Body:
application/json. - Auth: HTTP
Authorization: Bearer <api_key>(sent viaAuth::Bearer). - Endpoint:
POST https://api.sendgrid.com/v3/mail/send. - Quirks:
fromis an object ({email, name?}), not a string.- Recipients live under
personalizations[].to[], not a top-levelto:field. - Attachment field is
type(notcontent_type).
- Success:
202(no body — SendGrid returns the message ID in theX-Message-Idresponse header). Norq extracts it viaResponseHints.message_id_header = "X-Message-Id", not a JSON body path. - Retry: defaults — 429 + 5xx, 2 retries, 500ms backoff.