Why email infrastructure capability matters for an email parsing service
Email-infrastructure decisions shape everything that happens after a message hits your MX records. If your goal is to turn raw MIME into structured JSON that powers automations and internal tools, the path the message takes - MX routing, SMTP ingress, parsing, storage, and delivery - determines latency, reliability, and development effort. A robust pipeline should be easy to stand up for a proof of concept, scale without re-architecture, and handle the messy real world of email: nested multiparts, unusual charsets, oversized attachments, and occasional malformed headers.
This article compares two approaches to building scalable email processing pipelines: a specialized parser-first platform and Amazon SES, the AWS Simple Email Service. We focus specifically on email infrastructure capabilities - MX records, SMTP relays, API gateways, and how each solution moves messages from the public Internet to your application.
How MailParse handles email infrastructure
This platform centers the pipeline around instant inbound addresses and a parser built for developers. You can begin without DNS changes: create an address via API, receive messages immediately, and deliver structured JSON to your application via webhooks or pollable REST. For production, you can bring your own domain and point MX records to the provider’s SMTP ingress.
Ingress and MX
- Instant addresses - provisioned via API in seconds for rapid testing and per-workflow isolation.
- Custom domains - add your domain and set MX records to the service’s MX endpoints. No MTA to maintain.
- Plus addressing - route
support+ticket-123@yourdomain.comto capture metadata in the address string.
MIME parsing to JSON
On receipt, the SMTP relay forwards the raw message to a parsing engine that normalizes common edge cases. The output JSON typically includes:
- Message envelope and headers -
from,to,subject,messageId,inReplyTo, and full header map. - Body variants -
textandhtmlwith proper decoded charsets and quoted-printable handling. - Attachments - filename, content type, size, and either base64 content or time-limited URLs to download.
- Structure-awareness - nested multiparts, inline images with CID references, and alternative parts are flattened consistently.
Learn more about JSON output, MIME edge cases, and decoding in MIME Parsing: A Complete Guide | MailParse.
Delivery options: webhooks and REST
- Webhooks - push JSON to your HTTPS endpoint with a signing header and replay protection. Retries follow a backoff schedule with dead-letter visibility.
- REST polling - list messages by cursor, filter by recipient, and acknowledge processing idempotently to support batch jobs or restricted outbound networking.
For implementation details, see Webhook Integration: A Complete Guide | MailParse and Email Parsing API: A Complete Guide | MailParse.
Operational controls
- Routing - per-address rules to forward only what you need to particular webhooks or queues.
- Observability - event logs for delivery attempts, latency metrics, and parsing diagnostics to spot malformed content quickly.
- Scalability - horizontally scaled SMTP ingress and parser workers so throughput increases without customer-side changes.
How Amazon SES handles email infrastructure
Amazon SES is a powerful, general-purpose email service within AWS focused on sending and receiving at scale. For inbound pipelines, SES receives mail for your domain and then hands it off to the AWS services you choose. The building blocks are extremely flexible, but you assemble them yourself, often across multiple services: Route 53 or your DNS provider for MX, SES receipt rule sets, S3 for raw MIME storage, SNS for notifications, and Lambda for processing.
Ingress and MX
- Domain verification - you verify the domain in SES and prove ownership with DNS records.
- MX records - point your domain’s MX to SES inbound for your region, typically
inbound-smtp.<region>.amazonaws.com. - Receipt rule sets - define rules that match recipients or patterns and actions that run when mail arrives.
Actions and fan-out
- S3 action - store the raw RFC 822 message in an S3 bucket. Useful as the source of truth and for reprocessing.
- Lambda action - invoke a function with the raw content or S3 object pointer to parse and route.
- SNS action - publish a notification for further fan-out to SQS, HTTP subscribers, or other consumers.
MIME parsing and delivery
- No native JSON parsing - SES hands off raw MIME, so you use a library such as
mailparserin Node.js oremail/mailin Python or Ruby to build a JSON schema. - Delivery semantics - webhooks are not native. You create HTTP deliveries via SNS subscriptions or by calling APIs from Lambda.
- Reliability model - retries are handled by SNS or Lambda, not SES itself, so you manage backoff, dead letters, and idempotency in your architecture.
The result is an AWS-native pipeline that can be extremely scalable and customizable, though it typically carries a steeper learning curve and more moving parts than a parser-first service.
Side-by-side comparison
| Capability | MailParse | Amazon SES |
|---|---|---|
| Time to first inbound message | Minutes - instant address via API, no DNS needed | Hours - domain verification, MX updates, rule set deployment |
| Custom domains | Supported - add domain, set MX to hosted ingress | Supported - verify, point MX to SES inbound |
| Native MIME parsing to JSON | Yes - structured JSON for headers, parts, attachments | No - parse in Lambda or your app |
| Webhook delivery | Built in - signed requests, retries, idempotency keys | Via SNS or Lambda - you implement signing and idempotency |
| REST polling API | Yes - cursor-based listing and ack | No - fetch raw messages from S3 or use custom API |
| Attachment handling | Decoded with metadata and links or base64 | Raw MIME in S3 - parse and store attachment data yourself |
| Rule-based routing | Per-address routes to webhooks or queues | Receipt rules with S3, SNS, Lambda actions |
| Operational overhead | Low - one platform handles ingress, parsing, delivery | Medium to high - manage SES, S3, SNS, Lambda, IAM, and observability |
| AWS integration | Integrate via webhooks or REST | Deep - native to AWS with IAM and VPC options |
Code examples
Parser-first pipeline example: instant address, webhook, and REST
Create an inbound address and send test mail without touching DNS. Then process via webhook or poll via REST.
Provision an address via API:
curl -X POST https://api.your-email-parser.com/v1/addresses \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"label": "support-intake",
"webhook_url": "https://api.yourapp.com/inbound/email",
"routing": { "recipient_filter": ["support+*@example.com"] }
}'
Receive webhook deliveries with signature verification:
// Node.js - Express webhook handler
const crypto = require("crypto");
const express = require("express");
const app = express();
app.use(express.json({ limit: "25mb" })); // handle attachments
function verifySignature(req, secret) {
const sig = req.header("X-Signature");
const ts = req.header("X-Timestamp");
// Concatenate timestamp + body for HMAC signing
const payload = ts + JSON.stringify(req.body);
const hmac = crypto.createHmac("sha256", secret).update(payload).digest("hex");
return crypto.timingSafeEqual(Buffer.from(hmac), Buffer.from(sig));
}
app.post("/inbound/email", (req, res) => {
if (!verifySignature(req, process.env.WEBHOOK_SECRET)) {
return res.status(401).send("invalid signature");
}
const msg = req.body;
// Example: route tickets by plus-address key
// support+ticket-123@yourdomain.com
const plus = (msg.recipients[0] || "").split("+")[1]?.split("@")[0];
if (plus?.startsWith("ticket-")) {
// enqueue to your ticketing queue
}
// idempotency key provided in header X-Event-Id
res.status(200).send("ok");
});
app.listen(3000, () => console.log("webhook up"));
Alternatively, poll via REST when webhooks are not suitable:
# List messages with a cursor and acknowledge after processing
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.your-email-parser.com/v1/messages?limit=50&cursor=NEXT"
# After processing, acknowledge to prevent re-delivery
curl -X POST https://api.your-email-parser.com/v1/messages/ACK \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ids": ["msg_123", "msg_124"]}'
Amazon SES pipeline example: receipt rules, S3, and Lambda parsing
The following example routes inbound mail to S3 and invokes a Lambda function that parses MIME and posts structured JSON to your app.
1) Configure SES inbound for your domain and point MX to SES inbound for your region. Create a receipt rule set with actions: S3 store + Lambda invoke.
{
"Rule": {
"Name": "InboundToS3AndLambda",
"Enabled": true,
"TlsPolicy": "Optional",
"Recipients": ["support@example.com"],
"Actions": [
{
"S3Action": {
"BucketName": "inbound-raw-messages",
"ObjectKeyPrefix": "support/",
"KmsKeyArn": null
}
},
{
"LambdaAction": {
"FunctionArn": "arn:aws:lambda:us-east-1:123456789012:function:parse-inbound",
"InvocationType": "Event"
}
}
],
"ScanEnabled": true
}
}
2) Lambda function that reads the raw message from S3 and parses to JSON with the mailparser library, then delivers to your application.
// index.mjs - Node.js 18 Lambda
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
import fetch from "node-fetch";
import { simpleParser } from "mailparser";
const s3 = new S3Client({});
export const handler = async (event) => {
// SES passes S3 bucket and object key in the event
const record = event.Records[0].ses.mail.commonHeaders
? event.Records[0]
: event.Records[0]; // normalize if triggered by S3
const s3Record = event.Records[0].s3
? event.Records[0].s3
: null;
let bucket, key;
if (s3Record) {
bucket = s3Record.bucket.name;
key = decodeURIComponent(s3Record.object.key.replace(/\+/g, " "));
} else {
// If invoked directly by SES Lambda action, pull S3 data from SES receipt
const rec = event.Records[0].ses.receipt.action;
bucket = rec.bucketName;
key = rec.objectKey;
}
const obj = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
const raw = await obj.Body.transformToString("utf-8");
const parsed = await simpleParser(raw);
const payload = {
from: parsed.from?.text,
to: parsed.to?.text,
subject: parsed.subject,
text: parsed.text,
html: parsed.html,
messageId: parsed.messageId,
headers: Object.fromEntries(parsed.headers),
attachments: parsed.attachments?.map(a => ({
filename: a.filename,
contentType: a.contentType,
size: a.size
// persist a.content if you need it - do not inline large binaries in JSON
}))
};
const resp = await fetch(process.env.INBOUND_ENDPOINT, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Source": "ses-lambda",
"X-Idempotency-Key": parsed.messageId || crypto.randomUUID()
},
body: JSON.stringify(payload)
});
if (!resp.ok) {
// let Lambda retry or publish to a dead-letter queue
throw new Error(`Delivery failed with ${resp.status}`);
}
};
3) Add observability. Use CloudWatch for Lambda metrics and set up an SQS dead-letter queue for failures. For strict networking, place the function in a VPC and use VPC endpoints for S3 and SNS. Ensure IAM permissions for SES to write to S3 and invoke Lambda are attached correctly.
Performance and reliability in real-world email
Latency and throughput
- Parser-first flow - a message goes from SMTP ingress to JSON and into your app in a single pipeline. With webhooks, end-to-end latency is typically a few seconds, with horizontal scale at the ingress and parser layers. Polling is available when inbound-only networks forbid public webhooks.
- SES flow - inbound mail lands at SES, then fans out through your rule set. If you store to S3 and trigger Lambda, each hop adds latency. Lambda cold starts can add hundreds of milliseconds, occasionally seconds, on low-traffic functions. Proper provisioned concurrency reduces variance at cost.
Edge-case handling
- MIME structure - nested multiparts and encoded headers are normalized by a dedicated parser in the first approach. In SES, quality depends on the library you choose and how you handle rare charsets or malformed boundaries.
- Large attachments - parser-first delivery can stream or link large attachments to avoid oversized webhooks. In SES, you control storage in S3 and can stream to downstream systems, which is flexible but requires engineering.
- Idempotency and retries - built-in idempotency keys and HMAC signing simplify webhook consumers in a parser-first model. With SES, SNS and Lambda provide retries, but you own idempotency keys, signature schemes, and poison message handling.
Operations and failure modes
- DNS - with instant addresses, you can defer DNS changes until later. SES requires DNS from day one.
- Regionality - SES resources are regional and quotas vary by region. Architect for multi-region if you need failover. Parser-first platforms typically abstract multi-region ingress behind one API.
- Observability - one platform gives you parsing diagnostics and delivery logs in a single place. SES uses CloudWatch, S3 logs, SNS metrics, and Lambda logs, which is powerful but distributed.
Verdict: which is better for email infrastructure?
If your priority is to get reliable, structured email data into your application quickly with minimal infrastructure, a parser-first service is the fastest path. You get instant addresses, hosted MX, native MIME parsing, signed webhooks, and a REST polling alternative - all without stitching together multiple subsystems.
If you are all-in on AWS, want to control every layer, and have teams comfortable with IAM, SNS, S3, and Lambda, Amazon SES is a strong foundation. It excels when you need tight integration with existing AWS services and have workload patterns that benefit from serverless elasticity. You will invest more upfront in orchestration and parsing, but you gain maximum customization within your account.
In short, choose the specialized service for speed and simplicity, especially for developer-focused parsing pipelines. Choose Amazon SES for deep AWS integration and custom control over each hop of the email-infrastructure path.
FAQ
Do I need to change MX records to start processing inbound email?
No for some platforms - you can create instant addresses and start receiving immediately. For production on your domain, you will add MX records. Amazon SES always requires domain verification and MX changes to receive mail to