Email Authentication Setup with Resend

This guide explains how to set up email authentication using Resend with Convex Auth.

Prerequisites

  1. Create a Resend account
  2. Generate an API key from your Resend dashboard
  3. Verify your sending domain (or use Resend's test domain for development)

Configuration

1. Environment Variables

Add these to your .env.local file:

# Resend API Key
RESEND_API_KEY="re_xxxxxxxxxxxx"

# From email address (must be verified in Resend)
AUTH_RESEND_FROM="PromptNow <noreply@yourdomain.com>"

# Your site URL (for email links)
SITE_URL="https://yourdomain.com"

2. Features Enabled

With the current setup, you get:

  • Email Verification on Sign Up: Users receive a 6-digit code to verify their email
  • Password Reset: Users can reset their password via email with a 6-digit code
  • Welcome Emails: New users receive a welcome email after registration
  • Password Change Notifications: Users are notified when their password changes

Email Templates

The email templates are defined in:

  • /convex/ResendOTP.ts - Verification and password reset emails
  • /convex/emails.ts - Welcome and notification emails

Customizing Email Templates

You can customize the email templates by modifying the HTML in the respective files:

// Example: Customize the verification email
async sendVerificationRequest({ identifier: email, token, provider }) {
  const { error } = await resend.emails.send({
    from: provider.from as string,
    to: [email],
    subject: "Your verification code", // Change subject
    html: `...`, // Customize HTML template
    text: `...`, // Customize plain text version
  });
}

Testing Email Flows

1. Sign Up with Email Verification

// In your sign-up component
await signIn("password", {
  flow: "signUp",
  email: "user@example.com",
  password: "password123"
});
// User receives verification code email

2. Password Reset

// Initiate password reset
await signIn("password", {
  flow: "reset",
  email: "user@example.com"
});
// User receives reset code email

// Submit reset code and new password
await signIn("password", {
  flow: "reset-verification",
  email: "user@example.com",
  code: "123456",
  newPassword: "newPassword123"
});

Troubleshooting

Common Issues

  1. No emails being sent

    • Check your Resend API key is correct
    • Verify your sending domain in Resend
    • Check Convex logs for errors
  2. "Failed to send verification email" error

    • Ensure RESEND_API_KEY is set in environment variables
    • Check that the from email is verified in Resend
  3. Email links not working

    • Verify SITE_URL is set correctly in environment variables
    • Ensure it matches your actual domain

Testing in Development

For local development, you can:

  1. Use Resend's test API key (starts with re_test_)
  2. Set SITE_URL to http://localhost:3003
  3. Use a verified email domain or Resend's test domain

Advanced Configuration

Rate Limiting

Resend automatically handles rate limiting, but you can implement additional controls:

// Add rate limiting to email sending
const lastEmailSent = await ctx.db
  .query("emailLogs")
  .withIndex("by_email", (q) => q.eq("email", email))
  .order("desc")
  .first();

if (lastEmailSent && Date.now() - lastEmailSent.sentAt < 60000) {
  throw new Error("Please wait before requesting another email");
}

Email Analytics

Track email events using Resend webhooks:

  1. Set up webhook endpoint in your API
  2. Configure webhook URL in Resend dashboard
  3. Handle events (delivered, opened, clicked, etc.)

Security Considerations

  1. Verification Code Expiry: Codes expire after 15 minutes
  2. One-Time Use: Each code can only be used once
  3. Rate Limiting: Implement rate limiting to prevent abuse
  4. Secure Random Codes: Using 6-digit numeric codes generated securely

Production Checklist

  • Set up production Resend API key
  • Verify production sending domain
  • Update AUTH_RESEND_FROM with production email
  • Set correct SITE_URL for production
  • Test all email flows in production
  • Set up email monitoring/alerts
  • Configure SPF/DKIM records for better deliverability

On this page