SendGrid Bridge
Drop-in replacement for the SendGrid v3 Mail Send API — use your wemail API key, keep your existing request structure.
The SendGrid bridge lets you migrate from SendGrid to wemail without changing your integration code. Point your base URL to https://api.wemail.io/bridge/sendgrid, swap your SendGrid API key for a wemail API key, and keep the same request bodies, headers, and response shapes. The bridge translates every call into the wemail pipeline — delivery, tracking, webhooks, and suppressions all work the same way.
API Version & Authentication
| Parameter | Type | Required | Description |
|---|---|---|---|
API Version | v3 | Optional | Matches SendGrid v3 URL structure. |
Auth Method | Bearer Token | Optional | Authorization: Bearer afn_live_YOUR_KEY |
Base URL | URL | Optional | https://api.wemail.io/bridge/sendgrid |
Supported Endpoints
| Parameter | Type | Required | Description |
|---|---|---|---|
POST /v3/mail/send | Supported | Optional | Personalizations, content, templates, tracking, categories, custom_args, headers, CC/BCC, reply_to, send_at, substitutions. |
GET /v3/messages | Supported | Optional | List recent messages with limit param. opens_count and clicks_count always return 0. |
GET /v3/suppression/bounces | Supported | Optional | List bounces with start_time, end_time, limit filtering. |
GET /v3/suppression/spam_reports | Supported | Optional | List spam reports with start_time, end_time, limit filtering. |
SendGrid v3 API Compatibility Matrix
| Parameter | Type | Required | Description |
|---|---|---|---|
Mail Send (POST /v3/mail/send) | Supported | Optional | Personalizations, content, templates, tracking, categories, CC/BCC, reply_to, send_at. Attachments not yet supported. |
Email Activity / Messages (GET /v3/messages) | Partially Supported | Optional | List recent messages with limit. opens_count and clicks_count hardcoded to 0. No query filter support. |
Suppressions — Bounces | Supported | Optional | List with time range filtering. Delete/get individual bounce not supported. |
Suppressions — Spam Reports | Supported | Optional | List with time range filtering. Delete/get individual not supported. |
Suppressions — Blocks | Not Supported | Optional | — |
Suppressions — Invalid Emails | Not Supported | Optional | — |
Suppressions — Unsubscribes (Global) | Not Supported | Optional | — |
Templates / Dynamic Templates | Not Supported | Optional | template_id can be passed in mail/send but template CRUD is not available. |
Contacts / Marketing | Not Supported | Optional | Marketing campaigns, lists, segments, contacts. |
Stats (Global/Category/Subuser) | Not Supported | Optional | — |
Subuser Management | Not Supported | Optional | — |
IP Management (IPs, Pools, Warmup) | Not Supported | Optional | — |
Domain Authentication | Not Supported | Optional | Use wemail console for domain management. |
Link Branding | Not Supported | Optional | — |
Webhooks (Event/Inbound Parse) | Not Supported | Optional | Use wemail webhook configuration. |
Sender Verification | Not Supported | Optional | — |
API Keys Management | Not Supported | Optional | Use wemail console for API key management. |
Teammates | Not Supported | Optional | — |
Categories | Not Supported | Optional | Categories can be set via mail/send but CRUD is not available. |
Alerts | Not Supported | Optional | — |
Scheduled Sends (Cancel/Pause) | Not Supported | Optional | send_at supported in mail/send but cancel/pause not available. |
Email Validation | Not Supported | Optional | Use wemail /v3/validate endpoint instead. |
Field-Level Compatibility
Detailed breakdown of every request field and response field across all supported endpoints.
POST /v3/mail/send — Request Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
personalizations[].to | Supported | Required | Array of { email, name } recipients. At least one required. |
personalizations[].cc | Supported | Optional | CC recipients. |
personalizations[].bcc | Supported | Optional | BCC recipients. |
personalizations[].subject | Supported | Optional | Overrides top-level subject for this personalization. |
personalizations[].substitutions | Supported | Optional | Key-value string replacements applied to content. |
personalizations[].custom_args | Supported | Optional | Merged with top-level custom_args as metadata. |
personalizations[].send_at | Supported | Optional | Unix timestamp. Overrides top-level send_at. |
personalizations[].headers | Supported | Optional | Merged with top-level headers. |
personalizations[].dynamic_template_data | Not Supported | Optional | Ignored. Use substitutions instead. |
from | Supported | Required | { email, name }. Domain must be verified in your account. |
reply_to | Supported | Optional | { email, name } reply-to address. |
subject | Supported | Optional | Required unless template_id is set or every personalization has a subject. |
content[].type | Supported | Optional | text/html and text/plain supported. |
content[].value | Supported | Optional | The email body content. |
template_id | Supported | Optional | Passed through to wemail template engine. |
categories | Supported | Optional | Mapped to wemail tags (max 10). |
custom_args | Supported | Optional | Stored as message metadata. |
send_at | Supported | Optional | Unix timestamp for scheduled delivery. |
headers | Supported | Optional | Custom email headers. |
tracking_settings.open_tracking.enable | Supported | Optional | Enable/disable open tracking. |
tracking_settings.click_tracking.enable | Supported | Optional | Enable/disable click tracking. |
attachments | Not Supported | Optional | Silently ignored. Message sends without attachments. |
asm (unsubscribe groups) | Not Supported | Optional | Ignored. |
mail_settings | Not Supported | Optional | Ignored (sandbox_mode, bcc, footer, spam_check). |
batch_id | Not Supported | Optional | Ignored. Cancel/pause scheduled sends not available. |
ip_pool_name | Not Supported | Optional | Ignored. |
POST /v3/mail/send — Response
| Parameter | Type | Required | Description |
|---|---|---|---|
Status 202 | Supported | Optional | Empty body on success (matches SendGrid). |
X-Message-Id header | Supported | Optional | wemail message ID in response header. |
errors[] | Supported | Optional | On failure: { message, field, help } matching SendGrid error format. |
GET /v3/messages — Request & Response
| Parameter | Type | Required | Description |
|---|---|---|---|
limit (query) | Supported | Optional | Max results (default 50, max 1000). |
query (query) | Not Supported | Optional | SendGrid query filter syntax not implemented. |
Response: msg_id | Supported | Optional | wemail message ID. |
Response: from_email | Supported | Optional | Sender address. |
Response: to_email | Supported | Optional | First recipient. |
Response: subject | Supported | Optional | Message subject. |
Response: status | Supported | Optional | Mapped: queued->processing, sent->processed, delivered->delivered, bounced->not_delivered. |
Response: opens_count | Hardcoded 0 | Optional | Always returns 0. Use wemail events API. |
Response: clicks_count | Hardcoded 0 | Optional | Always returns 0. Use wemail events API. |
Response: last_event_time | Supported | Optional | ISO 8601 timestamp. |
GET /v3/suppression/bounces — Request & Response
| Parameter | Type | Required | Description |
|---|---|---|---|
start_time (query) | Supported | Optional | Unix timestamp filter. |
end_time (query) | Supported | Optional | Unix timestamp filter. |
limit (query) | Supported | Optional | Default 100, max 500. |
offset (query) | Not Supported | Optional | Accepted but ignored. |
Response: email | Supported | Optional | Bounced email address. |
Response: reason | Supported | Optional | Bounce reason. |
Response: status | Hardcoded | Optional | Always 5.1.1. |
Response: created | Supported | Optional | Unix timestamp. |
GET /v3/suppression/spam_reports — Request & Response
| Parameter | Type | Required | Description |
|---|---|---|---|
start_time (query) | Supported | Optional | Unix timestamp filter. |
end_time (query) | Supported | Optional | Unix timestamp filter. |
limit (query) | Supported | Optional | Default 100, max 500. |
Response: email | Supported | Optional | Complainant email. |
Response: reason | Supported | Optional | Complaint reason. |
Response: created | Supported | Optional | Unix timestamp. |
Response: ip | Hardcoded | Optional | Always empty string. |
SDK Downloads
Download the official SendGrid SDK pre-configured for the wemail bridge. The base URL is already set to https://api.wemail.io/bridge/sendgrid — just unzip and use with your wemail API key.
| Language | Package | Install | Registry |
|---|---|---|---|
| Node.js | @sendgrid/mail | | npm |
| Python | sendgrid | | PyPI |
| PHP | sendgrid/sendgrid | | Packagist |
| Ruby | sendgrid-ruby | | RubyGems |
| Go | sendgrid-go | | GitHub |
| Java | sendgrid-java | | Maven |
| C# | SendGrid | | NuGet |
Known Deviations from SendGrid API
Attachments — The attachments array in POST /v3/mail/send is not yet supported. Requests that include attachments will send the message without them.
Error format — Errors match the SendGrid structure: { "errors": [{ "message": "...", "field": "...", "help": "..." }] }.
Auto-creation — The bridge account is automatically created on the first authenticated request. No setup step is required.
Status mapping — The status field in messages uses the SendGrid vocabulary: queued → processing, sent → processed, etc.
Migrating for good? Follow the SendGrid migration guide — templates and suppressions auto-import, and SendGrid stays warm for 30 days.
Code examples
curl -X POST https://api.wemail.io/bridge/sendgrid/v3/mail/send \
-H "Authorization: Bearer afn_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"personalizations": [
{
"to": [{ "email": "user@example.com" }]
}
],
"from": { "email": "sender@yourdomain.com" },
"subject": "Hello from wemail",
"content": [
{
"type": "text/html",
"value": "<p>Hello World</p>"
}
]
}'// Official SDK: npm i @sendgrid/mail
const client = require('@sendgrid/client');
const sgMail = require('@sendgrid/mail');
// Point the official SendGrid SDK at the wemail bridge
client.setApiKey('afn_live_YOUR_KEY');
client.setDefaultRequest('baseUrl', 'https://api.wemail.io/bridge/sendgrid');
sgMail.setClient(client);
await sgMail.send({
to: 'user@example.com',
from: 'sender@yourdomain.com',
subject: 'Hello from wemail',
html: '<p>Hello World</p>',
});# Official SDK: pip install sendgrid
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
message = Mail(
from_email='sender@yourdomain.com',
to_emails='user@example.com',
subject='Hello from wemail',
html_content='<p>Hello World</p>')
# Point the official SendGrid SDK at the wemail bridge
sg = SendGridAPIClient('afn_live_YOUR_KEY', host='https://api.wemail.io/bridge/sendgrid')
response = sg.send(message)
print(response.status_code) # 202<?php
// Official SDK: composer require sendgrid/sendgrid
$email = new \SendGrid\Mail\Mail();
$email->setFrom('sender@yourdomain.com');
$email->addTo('user@example.com');
$email->setSubject('Hello from wemail');
$email->addContent('text/html', '<p>Hello World</p>');
// Point the official SendGrid SDK at the wemail bridge
$sendgrid = new \SendGrid('afn_live_YOUR_KEY', ['host' => 'https://api.wemail.io/bridge/sendgrid']);
$response = $sendgrid->send($email);
echo $response->statusCode(); // 202# Official SDK: gem install sendgrid-ruby
require 'sendgrid-ruby'
include SendGrid
from = SendGrid::Email.new(email: 'sender@yourdomain.com')
to = SendGrid::Email.new(email: 'user@example.com')
content = SendGrid::Content.new(type: 'text/html', value: '<p>Hello World</p>')
mail = SendGrid::Mail.new(from, 'Hello from wemail', to, content)
# Point the official SendGrid SDK at the wemail bridge
sg = SendGrid::API.new(api_key: 'afn_live_YOUR_KEY', host: 'https://api.wemail.io/bridge/sendgrid')
response = sg.client.mail._('send').post(request_body: mail.to_json)
puts response.status_code # 202// Official SDK: go get github.com/sendgrid/sendgrid-go
package main
import (
"fmt"
"github.com/sendgrid/sendgrid-go"
"github.com/sendgrid/sendgrid-go/helpers/mail"
)
func main() {
from := mail.NewEmail("Sender", "sender@yourdomain.com")
to := mail.NewEmail("User", "user@example.com")
msg := mail.NewSingleEmail(from, "Hello from wemail", to, "", "<p>Hello World</p>")
// Point the official SendGrid SDK at the wemail bridge
request := sendgrid.GetRequest("afn_live_YOUR_KEY", "/v3/mail/send", "https://api.wemail.io/bridge/sendgrid")
request.Method = "POST"
request.Body = mail.GetRequestBody(msg)
response, err := sendgrid.API(request)
if err != nil {
panic(err)
}
fmt.Println(response.StatusCode) // 202
}// Official SDK: com.sendgrid:sendgrid-java
import com.sendgrid.*;
import com.sendgrid.helpers.mail.Mail;
import com.sendgrid.helpers.mail.objects.*;
public class SendGridBridge {
public static void main(String[] args) throws Exception {
Email from = new Email("sender@yourdomain.com");
Email to = new Email("user@example.com");
Content content = new Content("text/html", "<p>Hello World</p>");
Mail mail = new Mail(from, "Hello from wemail", to, content);
// Point the official SendGrid SDK at the wemail bridge
SendGrid sg = new SendGrid("afn_live_YOUR_KEY");
sg.setHost("api.wemail.io/bridge/sendgrid");
Request request = new Request();
request.setMethod(Method.POST);
request.setEndpoint("mail/send");
request.setBody(mail.build());
Response response = sg.api(request);
System.out.println(response.getStatusCode()); // 202
}
}// Official SDK: dotnet add package SendGrid
using SendGrid;
using SendGrid.Helpers.Mail;
// Point the official SendGrid SDK at the wemail bridge
var client = new SendGridClient(new SendGridClientOptions
{
ApiKey = "afn_live_YOUR_KEY",
Host = "https://api.wemail.io/bridge/sendgrid"
});
var msg = MailHelper.CreateSingleEmail(
new EmailAddress("sender@yourdomain.com"),
new EmailAddress("user@example.com"),
"Hello from wemail", "", "<p>Hello World</p>");
var response = await client.SendEmailAsync(msg);
Console.WriteLine((int)response.StatusCode); // 202// 202 Accepted — no response body
// (matches SendGrid behavior)