This guide covers how to configure the default *.aexy.email domain infrastructure behind an Aexy deployment.
Overview#
Aexy provides each workspace with a default email domain in the format {workspace-slug}.aexy.email. This enables AI agents to have their own email addresses (e.g., [email protected]) without requiring users to configure custom domains.
┌─────────────────────────────────────────────────────────────────────────┐
│ Aexy Email Infrastructure │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Inbound Flow: │
│ ┌──────────┐ ┌─────────────┐ ┌────────────┐ ┌─────────────┐ │
│ │ Email │───▶│ MX Record │───▶│ Backend │───▶│ Agent inbox│ │
│ │ Sender │ │ (provider) │ │ webhook │ │ triage │ │
│ └──────────┘ └─────────────┘ └────────────┘ └─────────────┘ │
│ │
│ Outbound Flow: │
│ ┌──────────┐ ┌─────────────┐ ┌────────────┐ ┌─────────────┐ │
│ │ AI Agent │───▶│ Routing │───▶│ Provider │───▶│ Recipient │ │
│ │ Response │ │ Service │ │ (SES/SG) │ │ │ │
│ └──────────┘ └─────────────┘ └────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Prerequisites#
- A domain for your Aexy deployment (e.g.,
aexy.emailormail.yourdomain.com) - Access to DNS management for the domain
- An email provider account (Amazon SES recommended)
- The Aexy backend reachable over HTTPS from your email provider (inbound mail is posted to it)
DNS Configuration#
1. MX Records (Inbound Email)#
Configure MX records to route incoming emails to your email provider:
# For Amazon SES (US East 1)
aexy.email. MX 10 inbound-smtp.us-east-1.amazonaws.com.
# For Amazon SES (EU West 1)
aexy.email. MX 10 inbound-smtp.eu-west-1.amazonaws.com.
# Wildcard for workspace subdomains
*.aexy.email. MX 10 inbound-smtp.us-east-1.amazonaws.com.
2. SPF Record (Sender Authorization)#
Add SPF records to authorize your email providers:
# Single provider (SES)
aexy.email. TXT "v=spf1 include:amazonses.com ~all"
# Multiple providers
aexy.email. TXT "v=spf1 include:amazonses.com include:sendgrid.net include:mailgun.org ~all"
# Wildcard for subdomains
*.aexy.email. TXT "v=spf1 include:amazonses.com ~all"
3. DKIM Records (Email Signing)#
DKIM records are provider-specific and generated when you verify your domain:
Amazon SES:
# SES generates 3 CNAME records like:
abc123._domainkey.aexy.email. CNAME abc123.dkim.amazonses.com.
def456._domainkey.aexy.email. CNAME def456.dkim.amazonses.com.
ghi789._domainkey.aexy.email. CNAME ghi789.dkim.amazonses.com.
SendGrid:
s1._domainkey.aexy.email. CNAME s1.domainkey.u12345.wl.sendgrid.net.
s2._domainkey.aexy.email. CNAME s2.domainkey.u12345.wl.sendgrid.net.
4. DMARC Record (Policy)#
Add a DMARC record to specify how receiving servers should handle authentication failures:
_dmarc.aexy.email. TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]; pct=100"
DMARC Policy Options:
p=none- Monitor only, don't rejectp=quarantine- Send failures to spamp=reject- Reject authentication failures
5. Return-Path / Bounce Handling#
For proper bounce handling, configure a custom return-path subdomain:
bounce.aexy.email. MX 10 feedback-smtp.us-east-1.amazonses.com.
bounce.aexy.email. TXT "v=spf1 include:amazonses.com ~all"
Email Provider Setup#
Amazon SES Configuration#
-
Verify the Domain
aws ses verify-domain-identity --domain aexy.email aws ses verify-domain-dkim --domain aexy.email -
Request Production Access
- New SES accounts are in sandbox mode (limited sending)
- Request production access via AWS console
-
Configure Inbound Email Receipt
The inbound endpoint parses Postmark, SendGrid and Mailgun posts, and a plain JSON shape (
to,cc,from,from_name,subject,body,body_html,message_id,in_reply_to,headers). It does not unpack an SNS notification carrying a raw SES message, so with SES receiving you need a small relay (e.g. a Lambda on the SNS topic) that posts that JSON shape to/api/v1/webhooks/email/inbound.# Create an S3 bucket for email storage (optional) aws s3 mb s3://aexy-email-inbound # Create receipt rule set aws ses create-receipt-rule-set --rule-set-name aexy-inbound # Create receipt rule that publishes to the relay's SNS topic aws ses create-receipt-rule \ --rule-set-name aexy-inbound \ --rule '{ "Name": "forward-to-aexy", "Enabled": true, "Recipients": ["aexy.email"], "Actions": [{ "SNSAction": { "TopicArn": "arn:aws:sns:us-east-1:123456789:aexy-email-inbound", "Encoding": "UTF-8" } }] }' -
Set Active Receipt Rule Set
aws ses set-active-receipt-rule-set --rule-set-name aexy-inbound
SendGrid Configuration#
-
Authenticate Domain
- Go to Settings > Sender Authentication
- Add domain
aexy.email - Add the provided DNS records
-
Configure Inbound Parse
- Go to Settings > Inbound Parse
- Add
aexy.emailpointing tohttps://api.yourdomain.com/api/v1/webhooks/email/inbound?token=<INBOUND_EMAIL_WEBHOOK_TOKEN> - SendGrid does not sign Inbound Parse posts, so the token in the URL is the only thing that authenticates them
Mailgun Configuration#
-
Add Domain
- Go to Sending > Domains > Add New Domain
- Add
aexy.email - Configure DNS records as shown
-
Configure Routes for Inbound
Expression: match_recipient(".*@.*\.aexy\.email") Action: forward("https://api.yourdomain.com/api/v1/webhooks/email/inbound")
Inbound Webhook#
Inbound mail is handled by the backend itself — there is no separate email service. Every provider posts to one endpoint:
POST https://api.yourdomain.com/api/v1/webhooks/email/inbound
What happens to a post:
- It is authenticated (401 otherwise): Postmark Basic Auth, a Mailgun signature, or the shared token as
?token=/X-Aexy-Webhook-Token. - A registered Service Desk mailbox address takes it first and makes a ticket.
- Otherwise it is routed to the agent that owns the address (or, failing that, by the routing rules of the workspace the address belongs to) and saved to that agent's inbox.
- The Temporal activity
process_agent_inbox_messagetriages it — classify, escalate or draft — and, when the agent is set to auto-reply and the draft needs no review, sends the reply. See AI Agents → Agent inbox.
The Temporal worker must be running for step 4; without it messages still arrive and can be processed by hand with Process in the inbox.
Backend Configuration#
Environment Variables#
# Inbound webhook authentication (set the ones for your provider)
INBOUND_EMAIL_WEBHOOK_TOKEN=long-random-string # SendGrid / custom relays
POSTMARK_WEBHOOK_BASIC_AUTH=user:pass # Postmark inbound
MAILGUN_WEBHOOK_SIGNING_KEY=... # Mailgun routes
# Platform mailer (used for agent replies when a workspace has no sending provider)
EMAIL_PROVIDER=ses # ses | smtp | postmark
AWS_SES_REGION=us-east-1
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=...
Agent replies go through the workspace's default sending provider when it has one (Email Marketing → Settings), sending as the agent's address. Otherwise the platform mailer above sends them from the platform address with Reply-To set to the agent, so answers still come back to its inbox.
Database Configuration#
Run the email infrastructure migrations:
# Via Docker
docker exec aexy-backend python scripts/run_migrations.py
# Migrations include:
# - migrate_email_infrastructure.sql
# - migrate_agent_email.sql
Testing the Setup#
1. Verify DNS Records#
# Check MX record
dig MX aexy.email
# Check SPF record
dig TXT aexy.email
# Check DKIM
dig TXT abc123._domainkey.aexy.email
# Check DMARC
dig TXT _dmarc.aexy.email
2. Test Outbound Email#
# Send a test email via the API
curl -X POST "https://api.yourdomain.com/api/v1/email/test" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"subject": "Test Email",
"body": "This is a test email from Aexy"
}'
3. Test Inbound Email#
- Create a test agent with email enabled
- Send an email to
[email protected] - Check the agent's inbox in the UI or via API
# Check agent inbox
curl "https://api.yourdomain.com/api/v1/workspaces/$WORKSPACE_ID/crm/agents/$AGENT_ID/inbox" \
-H "Authorization: Bearer $TOKEN"
4. Verify Email Authentication#
Use email testing tools to verify SPF/DKIM/DMARC:
Production Checklist#
- DNS records configured (MX, SPF, DKIM, DMARC)
- Email provider domain verified
- SES production access approved (if using SES)
- Inbound email webhook configured
- Inbound webhook credential set (
INBOUND_EMAIL_WEBHOOK_TOKENor the provider's own scheme) - Temporal worker running (inbound triage and delayed replies)
- SSL certificates configured for webhook endpoints
- Bounce/complaint handling configured
- Monitoring and alerting set up
- Email authentication passing (SPF, DKIM, DMARC)
Troubleshooting#
Inbound Emails Not Received#
- Check MX records - Ensure they point to your provider
- Verify SES receipt rules - Make sure the rule set is active
- Check backend logs - Look for
Error handling inbound emailor a 401 from the webhook - Verify the provider's inbound route - Confirm it posts to
/api/v1/webhooks/email/inbound
# Check backend logs
docker logs aexy-backend -f --tail 100 | grep -i inbound
Outbound Emails Bouncing#
- Check sender domain verification - Domain must be verified in SES
- Verify SPF/DKIM - Use mail-tester.com to check
- Check SES sandbox mode - Request production access if needed
- Review bounce logs - Check for hard bounces
# Check SES sending statistics
aws ses get-send-statistics
DMARC Failures#
- Alignment issues - Ensure From domain matches SPF/DKIM domain
- Missing DKIM - Verify DKIM records are published
- SPF failures - Check all sending IPs are in SPF record
Agent Not Processing Emails#
- Check agent email is enabled - Verify in agent settings
- Check routing rules - Ensure email routes to correct agent
- Check the Temporal worker -
process_agent_inbox_messageruns there; its failures show in the Temporal UI (:8080) - Check the message's classification -
classification.auto_reply/classification.escalationsay what was decided and why a reply was held
Related Documentation#
- Email Marketing - Campaign and template management
- AI Agents - Agent configuration, tools and the agent inbox
- Deployment Guide - General deployment instructions