---
title: Email Integration
description: Complete guide for integrating Resend email service with Harmonic SaaS, including configuration, templates, and troubleshooting.
navigation:
  icon: i-solar-letter-line-duotone
---

# Email Integration Guide

## Overview

The email integration supports multiple delivery methods:
- **Resend** - Production email service (recommended)
- **SMTP/Nodemailer** - Generic SMTP support (e.g., for Mailpit in testing)
- **Mock Mode** - Console logging for development (no emails sent)

The system automatically selects the appropriate method based on your configuration.

## Configuration

### Environment Variables

Add these variables to your `.env` file:

```bash [.env]
# Email Service Configuration
NUXT_MOCK_EMAIL=true  # Set to 'true' to log emails instead of sending
NUXT_FROM_EMAIL=noreply@yourdomain.com
NUXT_APP_NAME=Harmonic SaaS

# Option 1: Resend (Production - recommended)
NUXT_RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxx

# Option 2: SMTP (for Mailpit or other SMTP servers)
# NUXT_SMTP_HOST=localhost
# NUXT_SMTP_PORT=1025
# NUXT_SMTP_SECURE=false
# NUXT_SMTP_USER=         # Optional
# NUXT_SMTP_PASSWORD=     # Optional
```

### Configuration Options

- **NUXT_MOCK_EMAIL**: Set to `true` to enable mock mode (log emails to console)
- **NUXT_FROM_EMAIL**: The email address that will appear as the sender
- **NUXT_APP_NAME**: Your application name (used in email subjects and content)

**For Resend:**
- **NUXT_RESEND_API_KEY**: Your Resend API key (get one at https://resend.com)

**For SMTP:**
- **NUXT_SMTP_HOST**: SMTP server hostname
- **NUXT_SMTP_PORT**: SMTP server port (typically 587 or 1025 for Mailpit)
- **NUXT_SMTP_SECURE**: Set to `true` for TLS/SSL
- **NUXT_SMTP_USER**: SMTP username (optional, not needed for Mailpit)
- **NUXT_SMTP_PASSWORD**: SMTP password (optional, not needed for Mailpit)

::tip
All environment variables use the `NUXT_` prefix which Nuxt automatically maps to the runtimeConfig. The system automatically selects the delivery method: SMTP if configured, otherwise Resend if API key is set, otherwise mock mode.
::

### Email Delivery Selection

The system automatically selects the email delivery method in this order:

1. **Mock Mode** - If `NUXT_MOCK_EMAIL=true` is set
2. **SMTP** - If `NUXT_SMTP_HOST` and `NUXT_SMTP_PORT` are configured
3. **Resend** - If `NUXT_RESEND_API_KEY` is configured
4. **Mock Mode (fallback)** - If none of the above are configured

When in mock mode, emails are logged to the console using `console.table` with the following format:

```
📧 Email Mock Mode - Email would be sent:
┌──────────┬────────────────────────────────────────┐
│ (index)  │ Values                                 │
├──────────┼────────────────────────────────────────┤
│ From     │ 'noreply@yourdomain.com'              │
│ To       │ 'user@example.com'                     │
│ Subject  │ 'Verify your Harmonic SaaS account'   │
└──────────┴────────────────────────────────────────┘

📝 Text Content:
Welcome to Harmonic SaaS!
...

🌐 HTML Content:
<!DOCTYPE html>...
```

This makes it easy to test email flows during local development without sending actual emails.

## Email Templates

The system includes four pre-built email templates:

### 1. Email Verification
**Function**: `sendVerificationEmail(email, name, url)`
- Sent when a user signs up
- Contains a verification link
- Styled HTML template with plain text fallback

### 2. Password Reset
**Function**: `sendPasswordResetEmail(email, name, url)`
- Sent when a user requests a password reset
- Contains a reset link (expires in 1 hour)
- Includes security notice about ignoring if not requested

### 3. Magic Link
**Function**: `sendMagicLinkEmail(email, url)`
- Sent for passwordless authentication
- Contains a sign-in link (expires in 15 minutes)
- Simple, secure authentication method

### 4. Team Invitation
**Function**: `sendTeamInvitationEmail(email, organizationName, inviterName, url)`
- Sent when a user is invited to join an organization
- Contains invitation link (expires in 7 days)
- Shows who invited them and organization name

## Implementation Details

### File Structure

```
server/utils/email.ts          # Email service and template functions
app/utils/auth.ts              # Better Auth configuration with email handlers
.env.example                   # Example environment variables
```

### Email Service (`server/utils/email.ts`)

The base `sendEmail()` function handles:
- Automatic delivery method selection (Mock/SMTP/Resend)
- SMTP integration via nodemailer
- Resend API integration
- Array or single recipient support
- HTML and text content
- Error handling and logging

### Better Auth Integration (`app/utils/auth.ts`)

Email handlers are configured in the Better Auth setup:
- `sendVerificationEmail`: Email verification flow
- `sendResetPassword`: Password reset flow
- `sendMagicLink`: Magic link authentication (plugin)
- `sendInvitationEmail`: Team invitations (organization plugin)

## Testing

### Mock Mode Testing

With `NUXT_MOCK_EMAIL=true` or no email service configured, emails will be logged to console.

### SMTP Testing (Mailpit)

For local E2E testing with real SMTP:

::steps
1. Start Mailpit: `pnpm test:db:up` (includes Mailpit)
2. Configure SMTP in `.env.test`:
   ```bash
   NUXT_MOCK_EMAIL=false
   NUXT_SMTP_HOST=localhost
   NUXT_SMTP_PORT=1025
   NUXT_SMTP_SECURE=false
   NUXT_FROM_EMAIL=noreply@test.local
   ```
3. View emails at http://localhost:8025
::

See [Mailpit Setup Guide](./2.mailpit-setup.md) for more details.

### Production Testing (Resend)

::steps
1. Sign up for a Resend account at https://resend.com
2. Create an API key
3. Verify your sending domain
4. Add `NUXT_RESEND_API_KEY` to your `.env` file
5. Test each email flow:
   - Sign up → Email verification
   - Forgot password → Password reset
   - Magic link sign in
   - Team invitation
::

## Customization

### Styling Email Templates

Email templates use inline CSS for maximum compatibility. To customize:

1. Edit the HTML in `server/utils/email.ts`
2. Maintain the text fallback versions
3. Test across different email clients
4. Use web-safe fonts and simple layouts

### Adding New Email Types

To add a new email template:

1. Create a new function in `server/utils/email.ts`:
```typescript
export async function sendCustomEmail(email: string, data: any) {
  const subject = 'Custom Email Subject'
  const html = `<!DOCTYPE html>...` // Your HTML template
  const text = `Plain text version`   // Text fallback

  return sendEmail({ to: email, subject, html, text })
}
```

2. Import and use in your API routes or Better Auth config

## Using Other Email Providers

The email system supports multiple providers out of the box:

### SMTP-Compatible Providers

Any SMTP-compatible service can be used via the SMTP configuration:
- **SendGrid** - Use their SMTP credentials
- **Mailgun** - Use their SMTP server
- **Amazon SES** - Use SMTP interface
- **Gmail/Outlook** - Use app-specific passwords

Just configure the SMTP environment variables with your provider's settings.

### Custom API Integrations

To add a custom provider API integration (like SendGrid API):

::steps
1. Install the provider's SDK: `pnpm add @sendgrid/mail`
2. Update `server/utils/email.ts`:
   - Add provider initialization similar to Resend
   - Update `sendEmail()` function to check for provider config
   - Keep the same function signatures
3. Update environment variables in `.env.example`
::

The rest of the application will continue to work unchanged.

## Database Migrations

The email integration uses Better Auth's built-in verification tables. Migrations have been applied:

```bash [Terminal]
pnpm db:generate  # Generate migration files
pnpm db:migrate   # Apply migrations to database
```

Database tables:
- `verification`: Stores email verification tokens
- `account`: OAuth and email accounts
- `session`: User sessions
- `user`: User data including `emailVerified` flag

## Troubleshooting

### Emails Not Being Sent

::accordion
:::accordion-item{title="Check API Key"}
Ensure `NUXT_RESEND_API_KEY` is correctly set in your environment variables.
:::

:::accordion-item{title="Verify Domain"}
In Resend dashboard, verify your sending domain to enable email delivery.
:::

:::accordion-item{title="Check FROM_EMAIL"}
Must be from a verified domain (`NUXT_FROM_EMAIL`). You cannot use free email providers.
:::

:::accordion-item{title="Review Logs"}
Check server console for error messages that might indicate configuration issues.
:::
::

### Emails Going to Spam

To improve email deliverability:

1. Set up SPF, DKIM, and DMARC records for your domain
2. Use a verified domain (not a free email provider)
3. Include both HTML and text versions
4. Avoid spam trigger words
5. Include unsubscribe links for marketing emails

### Development Mode Not Working

If console logging isn't working:
1. Ensure `NUXT_RESEND_API_KEY` is NOT set in `.env`
2. Check server console output
3. Verify the email function is being called

## Production Checklist

Before going live:

- [ ] Set up Resend account
- [ ] Verify your sending domain
- [ ] Configure SPF/DKIM/DMARC DNS records
- [ ] Set `NUXT_RESEND_API_KEY` in production environment
- [ ] Set `NUXT_FROM_EMAIL` to your domain
- [ ] Set `NUXT_APP_NAME` to your application name
- [ ] Test all email flows
- [ ] Monitor email delivery rates
- [ ] Set up email analytics/tracking if needed
- [ ] Configure rate limiting for email endpoints
- [ ] Review email content for branding consistency
- [ ] Test email rendering across clients (Gmail, Outlook, etc.)
