Automating Welcome Emails
Automating the First Touch: Instant Welcome Emails with Resend
The Problem
We successfully built a double opt-in subscription flow using Cloudflare D1 and Resend. However, once a user confirmed their email, the experience just... stopped. They were redirected to the homepage with a generic query parameter, and that was it. It felt transactional and cold. We needed a way to immediately deliver value—specifically, our latest blog post—and confirm to the user that they are truly "in."
The Solution
We automated the "Welcome" email sequence directly within the confirmation flow. Now, the moment a user clicks "Confirm," two things happen instantly:
- Frontend: They are redirected to a dedicated
/subscribe/successpage that confirms the action and visualizes success. - Backend: The
api/confirmendpoint validates the token, updates the database, and then immediately triggers a second email using the Resend API.
Crucially, we reused our existing listR2BlogPosts utility. This allows us to dynamically fetch the most recent blog post from our R2 bucket and insert a direct link to it in the welcome email. This turns a simple confirmation into an immediate content delivery system.
// src/pages/api/confirm.ts
// ... Update user status logic ...
// Send Welcome Email
if (env.RESEND_API_KEY) {
try {
const resend = new Resend(env.RESEND_API_KEY);
// Reuse existing R2 logic to get dynamic content
const posts = (await listR2BlogPosts(env)).sort(
(a, b) => new Date(b.frontmatter.pubDate).valueOf() - new Date(a.frontmatter.pubDate).valueOf(),
);
const latestPost = posts[0];
await resend.emails.send({
from: 'Rich <rich@news.richsd.com>',
to: [user.email],
subject: 'Welcome to Production-Ready AI!',
html: `... link to ${latestPost.slug} ...`
});
} catch (error) {
// Non-blocking error handling
console.error("Failed to send welcome email:", error);
}
}
The AI Angle
I leaned on the AI to quickly identify the integration point. I asked it to research the existing confirm.ts and subscribe.ts files. It correctly identified that confirm.ts was the perfect place to inject this logic because verifyng the token is the exact moment we know the user is legitimate. The AI also suggested ensuring the email sending was wrapped in a try-catch block so that if the email service fails, the user's confirmation isn't rolled back or errored out—a critical reliability detail.
Key Takeaways
- Immediate Value: Don't just confirm; deliver. The first interaction after sign-up is the highest leverage moment.
- Reuse Utilities: We didn't need a new "latest post" service; we just reused the logic that builds the homepage.
- Fail Gracefully: Secondary actions (like sending an email) should not block the primary action (confirming the user).