Salesforce + MailKite
Salesforce's default email relay uses its own infrastructure. Switch to MailKite to send from your own DKIM-signed domain — transactional, notifications, and flow-triggered emails all go through one pipeline with full deliverability control.
What you need
- A verified domain with SPF + DKIM published
- Your API key (
mk_live_…) - Salesforce edition with Email Relay (Professional, Enterprise, or Unlimited)
Configure the Email Relay
In Salesforce Setup, go to Email → Email Relay and add MailKite:
# Salesforce email relay SMTP settings
# Setup → Email → Email Relay
SMTP Host: smtp.mailkite.dev
Port: 587
Username: mailkite
Password: mk_live_...
TLS: Required (STARTTLS) Set the relay as the outbound gateway for your org. All Salesforce-originated email (alerts, flows, Apex sends) routes through MailKite.
Sending from Apex
Once the relay is configured, standard Apex email calls automatically route through MailKite. No code changes needed — the relay is org-wide:
// Apex: send email via Salesforce Email Relay (routed through MailKite)
Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
msg.setToAddresses(new String[] { 'customer@example.com' });
msg.setSubject('Invoice #INV-2024-001');
msg.setPlainTextBody('Your invoice is attached.');
msg.setHtmlBody('<p>Your invoice is attached.</p>');
msg.setUseSignature(false);
msg.setBccSender(false);
// The email relay handles DKIM signing via MailKite
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { msg }); Flows and email alerts
Record-triggered flows, scheduled flows, and email alerts all use the org's email relay. Configure them normally — they'll send through MailKite:
// Salesforce Flow: auto-send when Opportunity closes
// 1. Record-Triggered Flow on Opportunity (after update)
// 2. Condition: Stage = Closed Won
// 3. Action: Send Email (using Email Alert or Apex)
//
// The email goes through the org's Email Relay → MailKite
//
// No code needed — just configure the Email Alert and
// the Email Relay handles the rest. Receive inbound email → Cases
MailKite can POST inbound email to a webhook. Create Salesforce Cases from support emails:
// Receive inbound email -> create a Case in Salesforce
// Cloudflare Worker or any serverless function
export default {
async fetch(request, env) {
if (request.method !== "POST") return new Response("OK");
const payload = await request.json();
const { from, subject, text } = payload;
// Salesforce REST API -- create a Case
const sfRes = await fetch(
"https://" + env.SF_INSTANCE + ".salesforce.com/services/data/v58.0/sobjects/Case",
{
method: "POST",
headers: {
Authorization: "Bearer " + env.SF_ACCESS_TOKEN,
"Content-Type": "application/json",
},
body: JSON.stringify({
Subject: subject,
Description: text,
Origin: "Email",
Status: "New",
SuppliedEmail: from,
}),
}
);
return new Response(JSON.stringify({ created: sfRes.ok }), { status: 200 });
},
}; Set your domain's webhook to this endpoint. Every inbound email creates a new Case with the sender's email, subject, and body.
Troubleshooting
- Email Relay not available — Email Relay requires Professional Edition or higher. On Essentials, use the MailKite API from an external app.
- DKIM signing conflicts — Salesforce may add its own DKIM headers. If you see dual signatures, disable Salesforce's built-in DKIM in Setup → Email → DKIM Keys.
- Relay rejected — ensure the
Fromaddress is on a verified domain. Salesforce sometimes uses a no-reply address on a different domain. - Case not created — check the webhook logs. The Salesforce API requires an access token with
apiscope.
See the SMTP relay docs for connection details, or Send API for building custom Salesforce integrations.