Skip to content

Create inbound parse and security

Sengrids/twillios documentation about this: https://www.twilio.com/docs/sendgrid/for-developers/parsing-email/inbound-email

SendGrid Inbound Parse Webhook Setup Guide

This guide covers setting up an Inbound Parse Webhook, creating a security policy, and attaching the policy to your webhook.

Table of Contents

  1. Prerequisites
  2. MX Record Configuration
  3. Creating the Inbound Parse Webhook
  4. Creating a Security Policy
  5. Attaching Security Policy to Webhook
  6. Validating Incoming Webhooks
  7. Testing

Prerequisites

Before configuring Inbound Parse, ensure you have:

  • A SendGrid account with API access
  • A verified/authenticated domain in SendGrid
  • Access to your domain's DNS settings
  • A publicly accessible webhook endpoint (URL)
  • Your SendGrid API key with appropriate permissions

MX Record Configuration

Create an MX record in your DNS settings to route emails to SendGrid for parsing.

Field Value
Subdomain/Hostname Your parsing subdomain (e.g., parse)
Record Type MX
Priority 10
Mail Server mx.sendgrid.net
TTL Default (or 3600)

Example: For domain example.com, create MX record for parse.example.com pointing to mx.sendgrid.net.

Warning: Never modify MX records for your primary domain as this will disrupt normal email delivery.


Creating the Inbound Parse Webhook

Option A: Via SendGrid UI

  1. Log into your SendGrid account
  2. Navigate to Settings > Inbound Parse
  3. Click Add Host & URL
  4. Configure the following:
    • Hostname/Subdomain: Enter your parsing subdomain (e.g., parse)
    • Domain: Select your authenticated domain from the dropdown
    • Destination URL: Enter your webhook endpoint URL
  5. Configure additional options:
    • Spam Checking: Enable to scan emails (up to 2.5 MB) and include spam reports
    • Send Raw: Enable to receive full MIME messages with URL-encoded attachments
  6. Click Add to save

Option B: Via API

curl -X POST "https://api.sendgrid.com/v3/user/webhooks/parse/settings" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "url": "https://yourdomain.com/webhook/parse",
    "hostname": "parse.yourdomain.com",
    "spam_check": true,
    "send_raw": false
  }'

Webhook Configuration Options

Parameter Type Description
url string Required. The public URL where parsed emails will be POSTed
hostname string Required. The subdomain.domain that will receive emails
spam_check boolean Enable spam checking (emails ≤2.5 MB)
send_raw boolean Send full MIME message instead of parsed fields

Important Notes

  • The webhook URL must be publicly accessible
  • SendGrid will not follow redirects - use the final URL directly
  • Your endpoint must respond with a 2xx status code to confirm receipt
  • If your server returns 5xx errors, SendGrid will retry for up to 3 days
  • Maximum message size: 30 MB (including attachments)
  • Reserved email local-parts that cannot be used: abuse, postmaster, unsubscribe

Creating a Security Policy

Security policies ensure that webhook requests are authentic and originate from SendGrid. You can use:

  1. Signature Verification (ECDSA) - SendGrid signs payloads with a private key
  2. OAuth Verification - Validates requests with access tokens
  3. Both - Hybrid approach for enhanced security

API Endpoint

POST https://api.sendgrid.com/v3/user/webhooks/security/policies

Example: Signature-Only Policy

curl -X POST "https://api.sendgrid.com/v3/user/webhooks/security/policies" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "name": "parse-webhook-signature-policy",
    "signature": {
      "enabled": true
    }
  }'

Example: OAuth-Only Policy

curl -X POST "https://api.sendgrid.com/v3/user/webhooks/security/policies" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "name": "parse-webhook-oauth-policy",
    "oauth": {
      "client_id": "your_client_id",
      "client_secret": "your_client_secret",
      "token_url": "https://your-oauth-server.com/token",
      "scopes": ["webhooks:read", "webhooks:write"]
    }
  }'

Example: Hybrid Policy (Both Methods)

curl -X POST "https://api.sendgrid.com/v3/user/webhooks/security/policies" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "name": "parse-webhook-hybrid-policy",
    "oauth": {
      "client_id": "your_client_id",
      "client_secret": "your_client_secret",
      "token_url": "https://your-oauth-server.com/token",
      "scopes": ["webhooks:read", "webhooks:write"]
    },
    "signature": {
      "enabled": true
    }
  }'

Response

The API returns the created policy with its ID and public key (for signature verification):

{
  "id": "dd677638-a16d-4e19-95ea-20231c35511b",
  "name": "parse-webhook-signature-policy",
  "signature": {
    "enabled": true,
    "public_key": "MFkwEwYHKoZIzj0CAQYI..."
  }
}

Important: Store the public_key securely. You'll need it to verify incoming webhook signatures.


Attaching Security Policy to Webhook

Once you have created a security policy, attach it to your Inbound Parse webhook.

API Endpoint

PATCH https://api.sendgrid.com/v3/user/webhooks/parse/settings/{hostname}

Example Request

curl -X PATCH "https://api.sendgrid.com/v3/user/webhooks/parse/settings/parse.yourdomain.com" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "url": "https://yourdomain.com/webhook/parse",
    "spam_check": true,
    "send_raw": false,
    "security_policy": "dd677638-a16d-4e19-95ea-20231c35511b"
  }'

Replace dd677638-a16d-4e19-95ea-20231c35511b with your actual policy ID from the previous step.

Response

{
  "url": "https://yourdomain.com/webhook/parse",
  "hostname": "parse.yourdomain.com",
  "spam_check": true,
  "send_raw": false,
  "security_policy": "dd677638-a16d-4e19-95ea-20231c35511b"
}

Validating Incoming Webhooks

Signature Verification

When signature verification is enabled, SendGrid includes these headers with each request:

  • X-Twilio-Email-Event-Webhook-Signature - The ECDSA signature
  • X-Twilio-Email-Event-Webhook-Timestamp - Request timestamp

Verification Steps

  1. Extract the signature and timestamp from headers
  2. Get the raw request body (do not parse it first)
  3. Verify the ECDSA signature using the public key you stored earlier

Important Considerations

  • Inbound Parse uses multipart/form-data encoding
  • Do not parse the request body before validation - use the raw body exactly as received
  • Many web frameworks auto-parse multipart data; disable this behavior for validation

Example Verification (Python)

import hashlib
from ecdsa import VerifyingKey, BadSignatureError
from ecdsa.util import sigdecode_der

def verify_signature(public_key_base64, payload, signature, timestamp):
    """
    Verify SendGrid webhook signature.

    Args:
        public_key_base64: Base64 encoded public key from security policy
        payload: Raw request body (bytes)
        signature: X-Twilio-Email-Event-Webhook-Signature header value
        timestamp: X-Twilio-Email-Event-Webhook-Timestamp header value

    Returns:
        bool: True if signature is valid
    """
    import base64

    # Decode the public key
    public_key_bytes = base64.b64decode(public_key_base64)
    verifying_key = VerifyingKey.from_der(public_key_bytes)

    # Create the signed payload (timestamp + payload)
    signed_payload = timestamp.encode() + payload

    # Decode the signature
    signature_bytes = base64.b64decode(signature)

    try:
        verifying_key.verify(
            signature_bytes,
            signed_payload,
            hashfunc=hashlib.sha256,
            sigdecode=sigdecode_der
        )
        return True
    except BadSignatureError:
        return False

OAuth Verification

When OAuth is enabled, SendGrid includes an access token in the Authorization header:

Authorization: Bearer <access_token>

Validate this token against your OAuth server using standard OAuth token introspection.


Testing

Send a Test Email

  1. Send an email to your configured parsing address:
test@parse.yourdomain.com
  1. Check your webhook endpoint for the incoming POST request
  2. Verify the payload contains expected fields:
    • from - Sender email address
    • to - Recipient email address
    • subject - Email subject
    • text - Plain text body
    • html - HTML body (if present)
    • attachments - Number of attachments
    • SPF - SPF verification result
    • dkim - DKIM verification result

Webhook Payload Fields

Field Description
headers Raw email headers
from Sender email address
to Recipient email address
cc CC recipients
subject Email subject line
text Plain text body
html HTML body
sender_ip IP address of sending server
spam_report Spam analysis (if spam_check enabled)
spam_score Numeric spam score
SPF SPF verification result
dkim DKIM verification status
attachments Number of attachments
attachment-info JSON with attachment metadata
attachment1, attachment2, etc. Actual attachment files

Quick Reference

API Endpoints Summary

Action Method Endpoint
Create Parse Webhook POST /v3/user/webhooks/parse/settings
Get Parse Settings GET /v3/user/webhooks/parse/settings
Update Parse Webhook PATCH /v3/user/webhooks/parse/settings/{hostname}
Delete Parse Webhook DELETE /v3/user/webhooks/parse/settings/{hostname}
Create Security Policy POST /v3/user/webhooks/security/policies
Get Security Policies GET /v3/user/webhooks/security/policies
Get Security Policy GET /v3/user/webhooks/security/policies/{id}
Update Security Policy PATCH /v3/user/webhooks/security/policies/{id}
Delete Security Policy DELETE /v3/user/webhooks/security/policies/{id}

Base URL: https://api.sendgrid.com


References


Subpages