The Best Email Services for Transactional and Marketing Emails
Every web application needs to send email. Password resets, welcome messages, invoice receipts, notification digests — these are not optional features. They are part of the core experience. Get them wrong and your users do not trust your product. Get them right and nobody notices, which is exactly the point.
We have shipped transactional email across a dozen products using four different services. This post covers what we learned and which service we use for what.
The Services We Have Used
We have production experience with four email services:
- Resend — our current default for new projects
- SendGrid — used it for years, moved away from it
- Postmark — the best for pure transactional email
- AWS SES — the cheapest option by a wide margin
There are others (Mailgun, Mandrill, SparkPost), but these four cover the realistic options for most TypeScript-based web applications.
Resend: Our Default Choice
Resend is what we use for new projects. We adopted it in early 2024 for MindHyv and have since used it on VincelIO, Trackelio, and several client projects.
The reason is developer experience. Resend was built by developers for developers, and it shows. The API is clean, the SDK is tiny, and the integration with React Email means we can build email templates using the same component model we use for everything else.
Here is what sending an email looks like:
import { Resend } from 'resend';
import { WelcomeEmail } from '@/emails/welcome';
const resend = new Resend(process.env.RESEND_API_KEY);
await resend.emails.send({
from: 'MindHyv <hello@mindhyv.com>',
to: user.email,
subject: 'Welcome to MindHyv',
react: WelcomeEmail({ name: user.name }),
});
That is it. No transport configuration, no SMTP credentials, no template IDs. You pass a React component and the service renders it to HTML. The same email component can be previewed in the browser during development using npx react-email dev.
Here is what an email template looks like:
// emails/welcome.tsx
import {
Body,
Container,
Head,
Heading,
Html,
Link,
Preview,
Section,
Text,
} from '@react-email/components';
interface WelcomeEmailProps {
name: string;
}
export function WelcomeEmail({ name }: WelcomeEmailProps) {
return (
<Html>
<Head />
<Preview>Welcome to MindHyv — let's get you set up</Preview>
<Body style={bodyStyle}>
<Container style={containerStyle}>
<Heading style={headingStyle}>Welcome, {name}</Heading>
<Text style={textStyle}>
Thanks for signing up. Here is what to do next:
</Text>
<Section style={sectionStyle}>
<Text style={textStyle}>
1. Complete your profile{'\n'}
2. Connect your calendar{'\n'}
3. Set up your first service
</Text>
</Section>
<Link href="https://app.mindhyv.com/onboarding" style={linkStyle}>
Get Started
</Link>
</Container>
</Body>
</Html>
);
}
const bodyStyle = { backgroundColor: '#f6f9fc', fontFamily: 'sans-serif' };
const containerStyle = { margin: '0 auto', padding: '40px 20px', maxWidth: '560px' };
const headingStyle = { fontSize: '24px', fontWeight: '600', color: '#1a1a1a' };
const textStyle = { fontSize: '16px', lineHeight: '26px', color: '#4a4a4a' };
const sectionStyle = { padding: '24px', backgroundColor: '#ffffff', borderRadius: '8px' };
const linkStyle = {
display: 'inline-block',
padding: '12px 24px',
backgroundColor: '#5046e5',
color: '#ffffff',
borderRadius: '6px',
textDecoration: 'none',
fontSize: '14px',
fontWeight: '600',
};
The templating approach is the killer feature. Email HTML is notoriously awful — inline styles, table-based layouts, dozens of client-specific hacks. React Email abstracts all of that behind a component API. We write normal-looking components and get battle-tested HTML output that works in Gmail, Outlook, Apple Mail, and everything else.
Pricing: Free tier gives you 100 emails per day (3,000/month). Paid plans start at $20/month for 50,000 emails. Reasonable for most SaaS products.
Downsides: Resend is newer than the alternatives. The dashboard is simple — which is fine for us, but teams that want detailed analytics, A/B testing, or marketing automation features will find it lacking. It is a transactional email service first, and everything else second.

SendGrid: The Incumbent We Moved Away From
We used SendGrid for three years. It works. The deliverability is good. The feature set is comprehensive — transactional email, marketing campaigns, contact lists, templates, analytics, the works.
But the developer experience eroded over time. The API has grown complex with multiple versions and overlapping endpoints. The Node SDK is verbose:
import sgMail from '@sendgrid/mail';
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
await sgMail.send({
to: user.email,
from: {
email: 'hello@mindhyv.com',
name: 'MindHyv',
},
subject: 'Welcome to MindHyv',
templateId: 'd-a1b2c3d4e5f6',
dynamicTemplateData: {
name: user.name,
onboardingUrl: 'https://app.mindhyv.com/onboarding',
},
});
The template system uses a web-based drag-and-drop editor or Handlebars syntax. Both are frustrating for developers who want to version-control their templates and preview them locally. You end up with template IDs scattered across your codebase and no way to see what the email looks like without logging into the SendGrid dashboard.
Pricing: Free tier gives you 100 emails per day. Paid plans start at $20/month for 50,000 emails. The pricing is comparable to Resend, but the higher tiers get expensive, and the plan structure is confusing with different tiers for transactional versus marketing email.
When SendGrid still makes sense: If you need a single platform for both transactional email and marketing campaigns (newsletters, drip sequences, contact management), SendGrid is one of the few services that does both. For teams that want marketing features without adding a separate tool like Mailchimp, it is a reasonable choice.

Postmark: Best Deliverability for Transactional Email
Postmark is laser-focused on transactional email and it shows. They explicitly prohibit marketing email on their platform, which means their IP reputation is exceptionally clean. If deliverability is your top priority — if you absolutely cannot afford password reset emails landing in spam — Postmark is the safest choice.
import { ServerClient } from 'postmark';
const client = new ServerClient(process.env.POSTMARK_API_TOKEN);
await client.sendEmail({
From: 'hello@mindhyv.com',
To: user.email,
Subject: 'Welcome to MindHyv',
HtmlBody: htmlContent,
TextBody: textContent,
MessageStream: 'outbound',
});
The API is straightforward. The dashboard shows delivery stats with exceptional granularity — you can see exactly when an email was delivered, opened, clicked, and whether it bounced. The bounce management is automatic and handles suppression lists correctly.
Postmark also has a template system with a web editor and a JSON-based API for sending templated emails. The templates are versioned and can be managed via their CLI, which is better than SendGrid’s approach but still not as nice as React Email with Resend.
Pricing: Free trial with 100 emails. Paid plans start at $15/month for 10,000 emails. More expensive per-email than Resend or SendGrid, but the deliverability premium is real.
Downsides: No marketing email support at all. If you need to send newsletters or promotional campaigns, you need a second service. The template system is competent but not developer-friendly in the way React Email is.
AWS SES: Cheapest at Scale
If you are sending millions of emails per month, AWS SES is the only option that makes financial sense. At $0.10 per 1,000 emails, it is an order of magnitude cheaper than any alternative at scale.
import { SESv2Client, SendEmailCommand } from '@aws-sdk/client-sesv2';
const ses = new SESv2Client({ region: 'us-east-1' });
await ses.send(
new SendEmailCommand({
FromEmailAddress: 'hello@mindhyv.com',
Destination: {
ToAddresses: [user.email],
},
Content: {
Simple: {
Subject: { Data: 'Welcome to MindHyv' },
Body: {
Html: { Data: htmlContent },
Text: { Data: textContent },
},
},
},
})
);
The API is verbose and the SDK follows AWS’s typical pattern of wrapping everything in command objects. Not terrible, but not pleasant either.
The real cost of SES is not the per-email price — it is the operational overhead. You manage your own bounce handling, complaint processing, suppression lists, and deliverability monitoring. SES will throttle or suspend your account if your bounce rate exceeds their thresholds, and getting reinstated requires a support ticket. There is no built-in template management, no analytics dashboard, and no delivery tracking beyond basic CloudWatch metrics.
Pricing: $0.10 per 1,000 emails. If you are on EC2, the first 62,000 emails per month are free. Absurdly cheap at scale.
When SES makes sense: High-volume senders (100K+ emails per month) who have the engineering capacity to build bounce handling, suppression management, and delivery monitoring. Or teams already deep in the AWS ecosystem who want to minimize vendor count.

Our Recommendation by Use Case
Default choice for SaaS products: Resend. The developer experience is the best in the category, React Email templates are a genuine workflow improvement, and the deliverability is good. This is what we use for MindHyv, Trackelio, and most client projects.
When deliverability is critical: Postmark. Financial services, healthcare, anything where a missed email has real consequences. Pair it with a separate marketing email tool.
When you need marketing and transactional in one platform: SendGrid. Not our favorite developer experience, but the combined feature set is hard to beat if you want one vendor.
When you are sending at massive scale: AWS SES. But only if you have the engineering team to handle the operational complexity.
Setting Up Domain Authentication
Regardless of which service you choose, proper domain authentication is non-negotiable. All four services require you to add DNS records for SPF, DKIM, and ideally DMARC. This is not optional — without it, your emails will land in spam.
Here are the DNS records you typically need:
# SPF - allows the service to send on behalf of your domain
TXT @ v=spf1 include:_spf.resend.com ~all
# DKIM - cryptographically signs your emails
CNAME resend._domainkey resend._domainkey.resend.com
# DMARC - tells receiving servers what to do with unauthenticated email
TXT _dmarc v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com
The specifics vary by provider, but the pattern is the same. Set these up before you send your first email. Every service has a verification step that checks these records before allowing you to send from your domain.
React Email: The Template Layer
Regardless of which sending service you use, we recommend React Email for building templates. It works with all four services — you render the React component to HTML and pass the HTML string to whichever API you are using:
import { render } from '@react-email/render';
import { WelcomeEmail } from '@/emails/welcome';
// Works with any service
const html = await render(WelcomeEmail({ name: user.name }));
// Pass html to Postmark, SES, SendGrid, or any SMTP service
Resend has native React Email integration (you pass the component directly), but the render-to-HTML approach works everywhere. We wrote about our general approach to developer tooling in our post on our startup tech stack.
What We Actually Use in Production
Our standard setup for client projects:
- Resend for sending transactional emails
- React Email for building and previewing templates locally
- A shared email utility function that handles common patterns (retry logic, rate limiting, error logging)
- DNS authentication set up during the first week of the project
For marketing email (newsletters, product updates), we use a separate tool — usually Loops or Buttondown depending on the client’s needs. Keeping transactional and marketing email on separate services means better deliverability for the transactional side and purpose-built tools for the marketing side.
If you are building a product and need help setting up reliable email infrastructure, reach out at hello@threshline.com.