It Started With a Question in Discord
Someone in the Supabase Discord asked about email marketing this week. They wanted to set up onboarding emails, newsletters, user check-ins, and promotions. They were looking at Mailchimp and Audienceful.
Good tools. But the first thing I thought was: before picking a platform, there's something worth understanding. Not all emails are the same. And depending on which type you need, you might not need a marketing platform at all.
I know this because I went through the same thing building rolo.pet.
The Thing Nobody Tells You First
Transactional Emails
Triggered by something the user does. Automatic, one-to-one, expected.
- Welcome email after signup
- Password reset
- Approval notification
- Admin invitation
Event-driven. Something happens, email goes out.
Marketing Emails
Sent by you, on your schedule, to many people at once.
- Monthly newsletter
- Promotions
- Product updates
Campaign-driven. You write it, pick an audience, hit send.
Once I separated these two in my head, everything got simpler.
How It Started (rolo.pet)
I wasn't trying to build an email system. I was building rolo.pet and at some point I needed to send a welcome email when someone joined the waitlist.
So I told Claude Code: "when someone signs up for the waitlist, send them a welcome email with Resend."
It took a few back and forths. Setting up the Resend API key, verifying my domain, getting the edge function to actually trigger at the right time. But the core of it, the email logic itself, came from that one prompt. Edge function, Resend API call, deploy.
No Mailchimp account. No drag-and-drop editor. No separate marketing platform. And that's when it clicked: you can vibe code your entire email setup.
What I Actually Built
Here's what my email setup looks like today. All of this was vibe coded.
1. Waitlist Welcome Email
When someone joins the rolo.pet waitlist, they get a welcome email with a feature preview and an "invite a friend" link. The language (English or Spanish) depends on where the person is coming from. The whole thing fires automatically.
User joins waitlist
↓
INSERT on waitlist_users table
↓
Frontend calls send-waitlist-welcome edge function
↓
Resend sends branded welcome email
↓
Done. No manual step.The email has the rolo.pet branding, a 2x2 feature grid, and a pre-populated mailto link so they can invite friends. I described all of this in prompts and Claude Code built the HTML template inside the edge function.
2. Approval Email with Secure Token
When I approve someone from the waitlist, they get a role-based email (Owner, Vet, or Admin) with a validation link. The link has a UUID token that expires in 24 hours.
I approve a user
↓
Edge function generates a secure token
↓
Token stored in email_validation_tokens table (24hr TTL)
↓
Resend sends approval email with validation URL
↓
User clicks link → validated → access grantedThis one I especially didn't expect to vibe code. Secure tokens, expiry logic, role-based content. But honestly, I just described the flow and it happened.
3. Admin Invitation
When I need to add an admin to the panel, an edge function creates temporary credentials, stores an invitation token, and sends them an email with setup instructions.
Three different email flows, three edge functions, all built by describing what I wanted.
The Stack
Everything runs on Resend + Supabase Edge Functions.
- Resend handles the actual email delivery (free tier: 100 emails/day, 3,000 contacts)
- Supabase Edge Functions handle the logic (when to send, what content, token generation)
- Supabase Database stores tokens and tracks state
No separate email service. No marketing platform. It all lives in the same stack as the rest of the app.
The Basic Pattern
Every email function follows the same shape:
import { Resend } from "npm:resend";
const resend = new Resend(Deno.env.get("RESEND_API_KEY"));
Deno.serve(async (req) => {
const { record } = await req.json();
await resend.emails.send({
from: "hello@yourdomain.com",
to: record.email,
subject: "Welcome!",
html: "<p>Your branded HTML here</p>",
});
return new Response("sent", { status: 200 });
});You need: a Resend account, a verified domain, and a Supabase Edge Function. That's it.
Auth Emails Too
Supabase also has a send email hook that lets you customize magic links, confirmations, and password resets with your own Edge Function + Resend. So your users get branded emails from your domain instead of the default template.
Back to the Original Question
So for the person in Discord who wanted onboarding, newsletters, check-ins, and promotions:
Transactional (onboarding, check-ins, weekly updates) → Resend + Supabase Edge Functions. Describe what you want, vibe code it, deploy. It stays in your stack and runs automatically.
Marketing (newsletter, promotions) → you have options:
- Resend Broadcasts if you want to stay in one tool
- Mailchimp if you want visual editors and deep analytics
- Audienceful if you want something lighter
You can use Resend for transactional and a separate tool for campaigns. They don't need to be the same platform.
The Vibe Coding Part
Here's what I think is interesting: I didn't read Resend docs first. I didn't study email deliverability. I described what I wanted to happen and built from there.
"Send a welcome email when someone joins the waitlist. Make it bilingual. Add an invite-a-friend link."
"When I approve someone, send them a role-based email with a secure validation link that expires in 24 hours."
"Let me invite admins by email with temporary credentials."
Each of these prompts turned into a working edge function. The secure token logic, the HTML templates, the bilingual support. All vibe coded.
That doesn't mean you shouldn't understand what's happening. I do now. But the barrier to entry is way lower than it used to be.
And now when I want to communicate something to the people who follow my work, I don't have to go through a whole process. I just write, deploy, and it goes out. Everything stays in the same stack, in sync. No switching between platforms, no copy-pasting audiences. It's all right there.
You can build this in Lovable or in Claude Code, depending on your level. The setup is the same either way.
It's one of those things that hits different when you have context. Years ago, in my advertising days, sending a newsletter meant building everything from scratch. The copy, the images, the layout, the audience list, the scheduling. All manual. Multiple tools, multiple people, multiple rounds of review just to get one email out the door. Now I describe what I want and it ships. Same result, fraction of the process. Even the illustration in the welcome email was generated with AI and uploaded to Supabase Storage, all from the same workflow. Copy, design, delivery. One flow.
The Links
- Supabase: Sending Emails with Edge Functions
- Supabase: Custom Auth Emails with Resend
- Resend: Send with Supabase Edge Functions
- Lovable: Resend Integration
*I went from "I need to send a welcome email" to a full email system with three edge functions, secure tokens, and bilingual templates. All by describing what I wanted. That's the part that still surprises me.*
Speaking of Which
I liked this stack so much I built my own newsletter with it. Carol Ships is live. Same setup: Resend + Supabase Edge Function + a signup form in the footer of this site.
If you scroll down, you'll see it. Building, shipping, figuring it out. If that sounds like your kind of thing, I'd love to have you.