Resend Email Service Migration Guide¶
Date: November 7, 2025 Purpose: Migrate from Spacemail (non-functional SMTP) to Resend (working API) Estimated Time: 15-20 minutes Risk: Zero (test before canceling Spacemail)
Why Resend?¶
Spacemail Issues Discovered:
- Connection timeout on smtp.spacemail.com (ports 465, 587)
- Certificate mismatch on smtp.spacemail.io (uses AWS SES but unclear credentials)
- No SDK or REST API available
- Poor documentation
Resend Benefits: - โ Simple 3-line API (no SMTP configuration) - โ Excellent documentation - โ Official Node.js SDK - โ Free tier: 100 emails/day, 3,000/month - โ $20/month for 50,000 emails (beyond free tier) - โ 5-minute setup
Step 1: Sign Up for Resend¶
- Go to https://resend.com
- Click "Sign Up" (top right)
- Sign up with GitHub (easiest) or email
- Verify your email address
- Complete onboarding
Time: 2 minutes
Step 2: Get API Key¶
- Once logged in, go to API Keys section (left sidebar)
- Click "Create API Key"
- Name:
CodeSlick Production - Permission: Full Access (or "Sending Access" if available)
- Click "Create"
- Copy the API key (starts with
re_...) - Save it somewhere safe (you'll only see it once)
Example: re_123abc456def789ghi012jkl345mno678pqr
Time: 1 minute
Step 3: Verify Your Domain¶
3.1: Add Domain to Resend¶
- In Resend dashboard, go to Domains section
- Click "Add Domain"
- Enter:
codeslick.dev - Click "Add"
3.2: Get DNS Records¶
Resend will provide 3 DNS records (yours will be different):
Record 1: SPF (TXT)
Record 2: DKIM (TXT)
Record 3: Domain Verification (TXT)
3.3: Add DNS Records to Your Domain Registrar¶
Where is codeslick.dev registered? (Namecheap, GoDaddy, Cloudflare, etc.)
Example for Namecheap: 1. Log in to Namecheap 2. Go to Domain List โ codeslick.dev โ Manage 3. Click "Advanced DNS" tab 4. Click "Add New Record" 5. Add all 3 TXT records shown in Resend dashboard 6. Save changes
DNS Propagation: Wait 5-15 minutes (usually instant, max 1 hour)
3.4: Verify Domain in Resend¶
- Back in Resend dashboard โ Domains
- Click "Verify" next to
codeslick.dev - If verified: โ You'll see "Verified" status
- If not verified yet: Wait 5 more minutes, try again
Time: 5-10 minutes (including DNS propagation)
Step 4: Install Resend SDK¶
Time: 30 seconds
Step 5: Update Environment Variables¶
Local Development (.env.local)¶
Add these new variables:
# Resend Email Service (Production)
RESEND_API_KEY=re_your_api_key_here
RESEND_FROM_EMAIL=support@codeslick.dev
RESEND_FROM_NAME=CodeSlick
# Keep Mailtrap for local testing (optional)
MAILTRAP_HOST=sandbox.smtp.mailtrap.io
MAILTRAP_PORT=2525
MAILTRAP_USER=your_mailtrap_user
Remove or comment out Spacemail variables (keep as backup):
# OLD - Spacemail (not working, keeping as backup)
# SPACEMAIL_SECRET=xPYzhJ1ZVhmXVwQNKhWoAxVOiiuT0bCXlD8WrYIfNtmlbujUUYmNqScSFA270Bwp
# SPACEMAIL_FROM_EMAIL=support@codeslick.dev
# SPACEMAIL_FROM_NAME=CodeSlick
Production (Vercel)¶
- Go to Vercel โ Your Project โ Settings โ Environment Variables
- Add new variables:
RESEND_API_KEY=re_your_api_key_hereRESEND_FROM_EMAIL=support@codeslick.devRESEND_FROM_NAME=CodeSlick- Keep existing variables for now (as backup):
SPACEMAIL_SECRET(don't delete yet)SPACEMAIL_FROM_EMAIL(don't delete yet)SPACEMAIL_FROM_NAME(don't delete yet)- Click "Save"
- Redeploy (Vercel will prompt you)
Time: 2 minutes
Step 6: Create Resend Email Client¶
Create new file: src/lib/email/resend-client.ts
/**
* Resend Email Client
*
* Sends transactional emails using Resend API
* - Team invitations
* - Welcome emails
* - Payment confirmations
*
* Part of Phase 5 Week 2 - Email Service Migration
*/
import { Resend } from 'resend';
// Initialize Resend client
const resend = new Resend(process.env.RESEND_API_KEY);
/**
* Send team invitation email
*/
export async function sendTeamInvitationEmail({
to,
teamName,
inviterName,
invitationUrl,
}: {
to: string;
teamName: string;
inviterName: string;
invitationUrl: string;
}) {
try {
const { data, error } = await resend.emails.send({
from: `${process.env.RESEND_FROM_NAME} <${process.env.RESEND_FROM_EMAIL}>`,
to: [to],
subject: `You've been invited to join ${teamName} on CodeSlick`,
html: `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body style="margin: 0; padding: 0; font-family: Arial, sans-serif; background-color: #f5f5f5;">
<table width="100%" cellpadding="0" cellspacing="0" style="background-color: #f5f5f5; padding: 20px 0;">
<tr>
<td align="center">
<table width="600" cellpadding="0" cellspacing="0" style="background-color: #ffffff; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
<!-- Header -->
<tr>
<td style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 40px 20px; text-align: center;">
<h1 style="color: #ffffff; margin: 0; font-size: 28px; font-weight: bold;">
CodeSlick
</h1>
</td>
</tr>
<!-- Content -->
<tr>
<td style="padding: 40px 30px;">
<h2 style="color: #333333; margin: 0 0 20px 0; font-size: 24px;">
You've been invited to ${teamName}
</h2>
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 0 0 15px 0;">
${inviterName} has invited you to join their team on CodeSlick.
</p>
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 0 0 30px 0;">
CodeSlick provides automated security reviews for your GitHub pull requests, helping you catch vulnerabilities before they reach production.
</p>
<!-- CTA Button -->
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td align="center" style="padding: 20px 0;">
<a href="${invitationUrl}"
style="background-color: #667eea;
color: #ffffff;
text-decoration: none;
padding: 14px 40px;
border-radius: 6px;
font-size: 16px;
font-weight: bold;
display: inline-block;">
Accept Invitation
</a>
</td>
</tr>
</table>
<p style="color: #999999; font-size: 14px; line-height: 1.6; margin: 30px 0 0 0; text-align: center;">
This invitation will expire in 7 days
</p>
</td>
</tr>
<!-- Footer -->
<tr>
<td style="background-color: #f8f8f8; padding: 30px; text-align: center; border-top: 1px solid #eeeeee;">
<p style="color: #999999; font-size: 12px; line-height: 1.6; margin: 0;">
CodeSlick - Automated Security Reviews for GitHub PRs<br>
<a href="https://codeslick.dev" style="color: #667eea; text-decoration: none;">codeslick.dev</a>
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
`,
text: `
You've been invited to ${teamName} on CodeSlick
${inviterName} has invited you to join their team on CodeSlick.
CodeSlick provides automated security reviews for your GitHub pull requests.
Accept your invitation: ${invitationUrl}
This invitation will expire in 7 days.
---
CodeSlick - Automated Security Reviews for GitHub PRs
https://codeslick.dev
`.trim(),
});
if (error) {
console.error('โ Resend API error:', error);
return { success: false, error };
}
console.log(`โ
Invitation email sent to ${to} (Message ID: ${data?.id})`);
return { success: true, messageId: data?.id };
} catch (error) {
console.error('โ Failed to send invitation email:', error);
return { success: false, error };
}
}
/**
* Send welcome email to new users
*/
export async function sendWelcomeEmail({
to,
userName,
}: {
to: string;
userName: string;
}) {
try {
const { data, error } = await resend.emails.send({
from: `${process.env.RESEND_FROM_NAME} <${process.env.RESEND_FROM_EMAIL}>`,
to: [to],
subject: 'Welcome to CodeSlick!',
html: `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body style="margin: 0; padding: 0; font-family: Arial, sans-serif; background-color: #f5f5f5;">
<table width="100%" cellpadding="0" cellspacing="0" style="background-color: #f5f5f5; padding: 20px 0;">
<tr>
<td align="center">
<table width="600" cellpadding="0" cellspacing="0" style="background-color: #ffffff; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
<!-- Header -->
<tr>
<td style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 40px 20px; text-align: center;">
<h1 style="color: #ffffff; margin: 0; font-size: 28px; font-weight: bold;">
Welcome to CodeSlick!
</h1>
</td>
</tr>
<!-- Content -->
<tr>
<td style="padding: 40px 30px;">
<h2 style="color: #333333; margin: 0 0 20px 0; font-size: 24px;">
Hi ${userName}!
</h2>
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 0 0 15px 0;">
Thanks for signing up. You're all set to start securing your code.
</p>
<h3 style="color: #333333; margin: 30px 0 15px 0; font-size: 20px;">
Next Steps:
</h3>
<ol style="color: #666666; font-size: 16px; line-height: 1.8; margin: 0 0 30px 0; padding-left: 20px;">
<li>Install the CodeSlick GitHub App</li>
<li>Create or join a team</li>
<li>Open a pull request to see CodeSlick in action</li>
</ol>
<!-- CTA Button -->
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td align="center" style="padding: 20px 0;">
<a href="https://codeslick.dev/teams"
style="background-color: #667eea;
color: #ffffff;
text-decoration: none;
padding: 14px 40px;
border-radius: 6px;
font-size: 16px;
font-weight: bold;
display: inline-block;">
Get Started
</a>
</td>
</tr>
</table>
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 30px 0 0 0;">
Need help? Reply to this email or check our
<a href="https://codeslick.dev/help" style="color: #667eea; text-decoration: none;">documentation</a>.
</p>
</td>
</tr>
<!-- Footer -->
<tr>
<td style="background-color: #f8f8f8; padding: 30px; text-align: center; border-top: 1px solid #eeeeee;">
<p style="color: #999999; font-size: 12px; line-height: 1.6; margin: 0;">
CodeSlick - Automated Security Reviews for GitHub PRs<br>
<a href="https://codeslick.dev" style="color: #667eea; text-decoration: none;">codeslick.dev</a>
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
`,
text: `
Welcome to CodeSlick, ${userName}!
Thanks for signing up. You're all set to start securing your code.
Next Steps:
1. Install the CodeSlick GitHub App
2. Create or join a team
3. Open a pull request to see CodeSlick in action
Get Started: https://codeslick.dev/teams
Need help? Reply to this email or check our documentation: https://codeslick.dev/help
---
CodeSlick - Automated Security Reviews for GitHub PRs
https://codeslick.dev
`.trim(),
});
if (error) {
console.error('โ Resend API error:', error);
return { success: false, error };
}
console.log(`โ
Welcome email sent to ${to} (Message ID: ${data?.id})`);
return { success: true, messageId: data?.id };
} catch (error) {
console.error('โ Failed to send welcome email:', error);
return { success: false, error };
}
}
/**
* Send payment confirmation email
*/
export async function sendPaymentConfirmationEmail({
to,
teamName,
amount,
planName,
}: {
to: string;
teamName: string;
amount: number;
planName: string;
}) {
const formattedAmount = `โฌ${(amount / 100).toFixed(2)}`;
try {
const { data, error } = await resend.emails.send({
from: `${process.env.RESEND_FROM_NAME} <${process.env.RESEND_FROM_EMAIL}>`,
to: [to],
subject: 'Payment Confirmed - CodeSlick',
html: `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body style="margin: 0; padding: 0; font-family: Arial, sans-serif; background-color: #f5f5f5;">
<table width="100%" cellpadding="0" cellspacing="0" style="background-color: #f5f5f5; padding: 20px 0;">
<tr>
<td align="center">
<table width="600" cellpadding="0" cellspacing="0" style="background-color: #ffffff; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
<!-- Header -->
<tr>
<td style="background: linear-gradient(135deg, #10b981 0%, #059669 100%); padding: 40px 20px; text-align: center;">
<h1 style="color: #ffffff; margin: 0; font-size: 28px; font-weight: bold;">
Payment Confirmed
</h1>
</td>
</tr>
<!-- Content -->
<tr>
<td style="padding: 40px 30px;">
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 0 0 30px 0;">
Thank you for your payment! Your ${planName} subscription for <strong>${teamName}</strong> is now active.
</p>
<table width="100%" cellpadding="10" cellspacing="0" style="background-color: #f8f8f8; border-radius: 6px; margin: 0 0 30px 0;">
<tr>
<td style="color: #666666; font-size: 14px; padding: 15px;">
<strong>Plan:</strong> ${planName}
</td>
</tr>
<tr>
<td style="color: #666666; font-size: 14px; padding: 15px; border-top: 1px solid #e5e5e5;">
<strong>Amount:</strong> ${formattedAmount}/month
</td>
</tr>
<tr>
<td style="color: #666666; font-size: 14px; padding: 15px; border-top: 1px solid #e5e5e5;">
<strong>Team:</strong> ${teamName}
</td>
</tr>
</table>
<!-- CTA Button -->
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td align="center" style="padding: 20px 0;">
<a href="https://codeslick.dev/teams"
style="background-color: #667eea;
color: #ffffff;
text-decoration: none;
padding: 14px 40px;
border-radius: 6px;
font-size: 16px;
font-weight: bold;
display: inline-block;">
Go to Dashboard
</a>
</td>
</tr>
</table>
<p style="color: #999999; font-size: 14px; line-height: 1.6; margin: 30px 0 0 0; text-align: center;">
You can manage your subscription anytime in your team settings
</p>
</td>
</tr>
<!-- Footer -->
<tr>
<td style="background-color: #f8f8f8; padding: 30px; text-align: center; border-top: 1px solid #eeeeee;">
<p style="color: #999999; font-size: 12px; line-height: 1.6; margin: 0;">
CodeSlick - Automated Security Reviews for GitHub PRs<br>
<a href="https://codeslick.dev" style="color: #667eea; text-decoration: none;">codeslick.dev</a>
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
`,
text: `
Payment Confirmed
Thank you for your payment! Your ${planName} subscription for ${teamName} is now active.
Plan: ${planName}
Amount: ${formattedAmount}/month
Team: ${teamName}
Go to Dashboard: https://codeslick.dev/teams
You can manage your subscription anytime in your team settings.
---
CodeSlick - Automated Security Reviews for GitHub PRs
https://codeslick.dev
`.trim(),
});
if (error) {
console.error('โ Resend API error:', error);
return { success: false, error };
}
console.log(`โ
Payment confirmation sent to ${to} (Message ID: ${data?.id})`);
return { success: true, messageId: data?.id };
} catch (error) {
console.error('โ Failed to send payment confirmation:', error);
return { success: false, error };
}
}
Time: Copy-paste (1 minute)
Step 7: Update Team Invitation API Endpoint¶
Update: src/app/api/teams/[id]/invitations/route.ts
Find this section (around line 272):
// Send invitation email via Spacemail (non-blocking)
if (process.env.SPACEMAIL_SECRET && process.env.SPACEMAIL_FROM_EMAIL) {
sendTeamInvitationEmail({
to: email,
teamName: team.name,
inviterName: auth.user.name || auth.user.email || 'A team member',
invitationUrl: inviteUrl,
}).catch((error) => {
// Log error but don't block the API response
console.error('[Team Invitations API] Failed to send invitation email:', error);
});
}
Replace the import at the top:
// OLD:
import { sendTeamInvitationEmail } from '@/lib/email/spacemail-smtp-client';
// NEW:
import { sendTeamInvitationEmail } from '@/lib/email/resend-client';
Update the email sending logic:
// Send invitation email via Resend (non-blocking)
if (process.env.RESEND_API_KEY && process.env.RESEND_FROM_EMAIL) {
sendTeamInvitationEmail({
to: email,
teamName: team.name,
inviterName: auth.user.name || auth.user.email || 'A team member',
invitationUrl: inviteUrl,
}).catch((error) => {
// Log error but don't block the API response
console.error('[Team Invitations API] Failed to send invitation email:', error);
});
} else {
// Development fallback: log invitation URL
console.log('๐ง INVITATION EMAIL (DEV MODE - no email service configured)');
console.log(` To: ${email}`);
console.log(` Team: ${team.name}`);
console.log(` Inviter: ${auth.user.name || auth.user.email}`);
console.log(` URL: ${inviteUrl}`);
}
Time: 2 minutes
Step 8: Test Locally (Optional but Recommended)¶
Create test script: scripts/test-resend-email.ts
/**
* Test Resend Email Sending
*
* Usage:
* npx tsx scripts/test-resend-email.ts
*/
import { loadEnvConfig } from '@next/env';
import { sendTeamInvitationEmail } from '../src/lib/email/resend-client';
loadEnvConfig(process.cwd());
async function testResendEmail() {
console.log('๐งช Testing Resend email configuration...\n');
// Check environment variables
console.log('Environment Variables:');
console.log(` RESEND_API_KEY: ${process.env.RESEND_API_KEY ? '***SET***' : 'NOT SET'}`);
console.log(` RESEND_FROM_EMAIL: ${process.env.RESEND_FROM_EMAIL || 'NOT SET'}`);
console.log(` RESEND_FROM_NAME: ${process.env.RESEND_FROM_NAME || 'NOT SET'}\n`);
if (!process.env.RESEND_API_KEY || !process.env.RESEND_FROM_EMAIL) {
console.error('โ Missing required environment variables');
console.error(' Required: RESEND_API_KEY, RESEND_FROM_EMAIL');
process.exit(1);
}
// Send test email
console.log('๐ง Sending test invitation email...\n');
const result = await sendTeamInvitationEmail({
to: 'vclourenco@protonmail.ch', // Your email
teamName: 'Test Team',
inviterName: 'Resend Test Script',
invitationUrl: 'https://codeslick.dev/invite/test-token-resend-123',
});
if (result.success) {
console.log('\nโ
Email sent successfully via Resend!');
console.log(` Message ID: ${result.messageId}`);
console.log('\n๐ Resend is working! Check your inbox (vclourenco@protonmail.ch)');
} else {
console.log('\nโ Email failed to send');
console.error(' Error:', result.error);
}
}
testResendEmail().catch(console.error);
Run test:
Expected output:
Check your email (vclourenco@protonmail.ch) - you should receive the invitation within 5-10 seconds.
Time: 3 minutes
Step 9: Deploy to Production¶
9.1: Commit Changes¶
git add .
git commit -m "feat: Migrate from Spacemail to Resend email service
- Install resend SDK
- Create resend-client.ts with 3 email templates
- Update team invitation API to use Resend
- Add RESEND_API_KEY environment variable support
- Test script confirms email delivery working
- Fixes: Email invitations not being delivered in production"
9.2: Push to Vercel¶
Vercel will automatically deploy (3-5 minutes).
9.3: Verify Environment Variables in Vercel¶
- Go to Vercel โ Project โ Settings โ Environment Variables
- Confirm these exist:
- โ
RESEND_API_KEY - โ
RESEND_FROM_EMAIL - โ
RESEND_FROM_NAME
Time: 5 minutes
Step 10: Test in Production¶
10.1: Send Test Invitation¶
- Go to https://codeslick.dev
- Sign in
- Go to your team โ Settings โ Members
- Click "Invite Member"
- Enter:
vclourenco@protonmail.ch - Click "Send Invitation"
10.2: Verify Email Received¶
- Check your inbox (vclourenco@protonmail.ch)
- Email should arrive within 5-10 seconds
- Check spam folder if not in inbox
10.3: Check Resend Dashboard¶
- Go to Resend dashboard โ Emails (or Logs)
- You should see the sent email with status "Delivered"
- Click on email to see full details
Time: 2 minutes
Step 11: Clean Up (After Confirming Resend Works)¶
11.1: Remove Spacemail Environment Variables¶
In Vercel:
1. Go to Settings โ Environment Variables
2. Delete:
- SPACEMAIL_SECRET
- SPACEMAIL_FROM_EMAIL (if separate from RESEND)
- SPACEMAIL_FROM_NAME (if separate from RESEND)
In .env.local:
11.2: Remove Old Files (Optional)¶
# Rename old file for reference
mv src/lib/email/spacemail-smtp-client.ts src/lib/email/spacemail-smtp-client.ts.backup
# Or delete if confident
rm src/lib/email/spacemail-smtp-client.ts
rm scripts/test-email.ts
rm scripts/test-spacemail-smtp.ts
11.3: Cancel Spacemail Subscription¶
- Log in to Spacemail
- Go to Billing or Subscription settings
- Cancel subscription
- Confirm cancellation
Time: 3 minutes
Troubleshooting¶
Issue 1: "Invalid API key" Error¶
Problem: RESEND_API_KEY is incorrect or not set
Fix:
1. Go to Resend dashboard โ API Keys
2. Verify your API key
3. Copy it again (create new one if needed)
4. Update .env.local or Vercel environment variables
5. Restart dev server or redeploy
Issue 2: "Domain not verified" Error¶
Problem: codeslick.dev not verified in Resend
Fix:
1. Check DNS records are correctly added
2. Use DNS checker: https://dnschecker.org
- Search for: codeslick.dev (TXT records)
- Should show Resend verification records
3. Wait 5-15 more minutes for propagation
4. Click "Verify" in Resend dashboard
Issue 3: Emails Going to Spam¶
Problem: SPF/DKIM records not configured correctly
Fix: 1. Verify all 3 DNS records are added (SPF, DKIM, verification) 2. Add DMARC policy (optional but helps):
3. Test email delivery with https://www.mail-tester.comIssue 4: "Rate limit exceeded" Error¶
Problem: Exceeded free tier (100 emails/day)
Fix: 1. Check Resend dashboard โ Usage 2. Upgrade to paid plan if needed ($20/month for 50k emails) 3. Implement rate limiting in application
Cost Comparison¶
| Service | Free Tier | Paid Tier | Current Status |
|---|---|---|---|
| Spacemail | Unknown | Unknown | Not working (SMTP timeout) |
| Resend | 100 emails/day 3,000/month |
$20/month 50,000 emails |
โ Recommended |
Beta Launch Estimate: - 10 beta users ร 1 invitation = 10 emails - 10 welcome emails = 10 emails - 5 payment confirmations = 5 emails - Total: ~25 emails (well within free tier)
Month 1 Estimate (after beta): - 50 new users ร 2 emails (welcome + invitation) = 100 emails - Total: ~100 emails/month (free tier sufficient)
Migration Checklist¶
- Step 1: Sign up for Resend account
- Step 2: Get API key from dashboard
- Step 3: Verify domain (add 3 DNS records)
- Step 4: Install
resendSDK (npm install resend) - Step 5: Add environment variables (local + Vercel)
- Step 6: Create
resend-client.tsfile - Step 7: Update invitation API endpoint
- Step 8: Test locally with test script
- Step 9: Deploy to production (commit + push)
- Step 10: Test in production (send real invitation)
- Step 11: Clean up (remove Spacemail variables)
- Step 12: Cancel Spacemail subscription
Success Criteria¶
โ Email sent successfully in local test โ Email sent successfully in production โ Email arrives within 10 seconds โ Email not in spam folder โ Resend dashboard shows "Delivered" status โ Production invitation flow works end-to-end
Next Steps After Migration¶
- Test all 3 email types:
- Team invitation โ
- Welcome email (on sign-up)
-
Payment confirmation (after Stripe payment)
-
Monitor email delivery:
- Check Resend dashboard daily
- Monitor bounce rates
-
Watch for spam complaints
-
Set up email templates in Resend (optional):
- Go to Resend โ Templates
- Create reusable templates
- Reference templates by ID instead of HTML strings
Support Resources¶
Resend Documentation: https://resend.com/docs/introduction Resend Node.js SDK: https://resend.com/docs/send-with-nodejs Resend Status Page: https://status.resend.com DNS Checker: https://dnschecker.org Email Tester: https://www.mail-tester.com
Document Created: November 7, 2025 Migration Status: Ready to Execute Estimated Total Time: 15-20 minutes Risk Level: Zero (test before canceling Spacemail)
Next Action: Execute Step 1 (Sign up for Resend)