Match an exact address, a domain wildcard, a plus-addressed pattern like ticket+*@yourapp.com, or a regex — and route each match to a webhook, a forward address, storage-only, a drop, or a built-in AI agent. It's the same engine behind catch-all, multi-tenant addressing, and inbox agents.
An exact address, a domain-wide *@yourapp.com, a plus-addressed pattern like ticket+*@yourapp.com, or a full regex — pick whatever shape your addresses take.
webhook, forward, store (no delivery, still recorded), drop (discard), or agent (a prompt-driven AI reply) — each route picks one.
Add, edit, or remove a route from the dashboard or the API — reshaping how mail flows doesn't require touching your webhook handler.
Whatever the action, the inbound message is recorded so you can list, inspect, and replay it later — routing doesn't cost you visibility.
Pick an exact address, a domain wildcard, a plus-addressed pattern, or a regex for the slice of mail this rule covers.
webhook (with a destination URL), forward (to an address), store, drop, or agent (with a prompt).
Add it from the dashboard or POST /api/routes — it takes effect on the next matching message, no redeploy.
Same createRoute call, four match shapes, five actions — the rules engine behind every solution on this page.
Dashboard → Routes → [ + New route ]
Match ticket+*@yourapp.com
Action Webhook
Destination https://yourapp.com/hooks/tickets
Click [ Save ]
[ + New route ]
Match legal@yourapp.com
Action Forward
Destination counsel@lawfirm.com
Click [ Save ]Send ticket+*@yourapp.com to https://yourapp.com/hooks/tickets,
and forward legal@yourapp.com to counsel@lawfirm.comimport { MailKite } from "mailkite";
const mk = new MailKite(process.env.MAILKITE_API_KEY);
// Plus-addressed tickets go to a webhook; everything else on the
// domain falls through to whatever the domain's default route is.
await mk.createRoute({
match: "ticket+*@yourapp.com",
action: "webhook",
destination: "https://yourapp.com/hooks/tickets",
});
// A single address gets forwarded instead of parsed.
await mk.createRoute({
match: "legal@yourapp.com",
action: "forward",
destination: "counsel@lawfirm.com",
});import os
from mailkite import MailKite
mk = MailKite(os.environ["MAILKITE_API_KEY"])
# Plus-addressed tickets go to a webhook; everything else on the
# domain falls through to whatever the domain's default route is.
mk.createRoute({
"match": "ticket+*@yourapp.com",
"action": "webhook",
"destination": "https://yourapp.com/hooks/tickets",
})
# A single address gets forwarded instead of parsed.
mk.createRoute({
"match": "legal@yourapp.com",
"action": "forward",
"destination": "counsel@lawfirm.com",
})<?php
$mk = new \MailKite\Client(getenv('MAILKITE_API_KEY'));
// Plus-addressed tickets go to a webhook; everything else on the
// domain falls through to whatever the domain's default route is.
$mk->createRoute([
'match' => 'ticket+*@yourapp.com',
'action' => 'webhook',
'destination' => 'https://yourapp.com/hooks/tickets',
]);
// A single address gets forwarded instead of parsed.
$mk->createRoute([
'match' => 'legal@yourapp.com',
'action' => 'forward',
'destination' => 'counsel@lawfirm.com',
]);MailKite mk = new MailKite(System.getenv("MAILKITE_API_KEY"));
// Plus-addressed tickets go to a webhook; everything else on the
// domain falls through to whatever the domain's default route is.
mk.createRoute(Map.of(
"match", "ticket+*@yourapp.com",
"action", "webhook",
"destination", "https://yourapp.com/hooks/tickets"
));
// A single address gets forwarded instead of parsed.
mk.createRoute(Map.of(
"match", "legal@yourapp.com",
"action", "forward",
"destination", "counsel@lawfirm.com"
));mk := mailkite.New(os.Getenv("MAILKITE_API_KEY"))
// Plus-addressed tickets go to a webhook; everything else on the
// domain falls through to whatever the domain's default route is.
_, err := mk.CreateRoute(map[string]any{
"match": "ticket+*@yourapp.com",
"action": "webhook",
"destination": "https://yourapp.com/hooks/tickets",
})
// A single address gets forwarded instead of parsed.
_, err = mk.CreateRoute(map[string]any{
"match": "legal@yourapp.com",
"action": "forward",
"destination": "counsel@lawfirm.com",
})require "mailkite"
mk = Mailkite::Client.new(ENV["MAILKITE_API_KEY"])
# Plus-addressed tickets go to a webhook; everything else on the
# domain falls through to whatever the domain's default route is.
mk.createRoute(
"match" => "ticket+*@yourapp.com",
"action" => "webhook",
"destination" => "https://yourapp.com/hooks/tickets"
)
# A single address gets forwarded instead of parsed.
mk.createRoute(
"match" => "legal@yourapp.com",
"action" => "forward",
"destination" => "counsel@lawfirm.com"
)# Plus-addressed tickets go to a webhook; everything else on the
# domain falls through to whatever the domain's default route is.
curl https://api.mailkite.dev/api/routes \
-H "Authorization: Bearer $MAILKITE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"match": "ticket+*@yourapp.com",
"action": "webhook",
"destination": "https://yourapp.com/hooks/tickets"
}'
# A single address gets forwarded instead of parsed.
curl https://api.mailkite.dev/api/routes \
-H "Authorization: Bearer $MAILKITE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"match": "legal@yourapp.com",
"action": "forward",
"destination": "counsel@lawfirm.com"
}' It falls through to the domain's default behavior — typically a catch-all webhook — so nothing silently disappears just because no specific rule matched.
Yes — ticket+*@yourapp.com (or any prefix before the +) matches the whole family of addresses, which is how multi-tenant and per-signup addressing work without pre-creating each one.
Most routes use exact, domain-wildcard, or plus-addressed matching. Regex is there for the address shapes those three don't cover.
Start free on unlimited domains — no credit card. Or browse the other solutions.