Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
191 changes: 191 additions & 0 deletions VERCEL_EMAIL_SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# Vercel Deployment - Gmail Email Configuration Guide

## 🚨 Current Issue: Gmail Authentication Failed

The forms are working correctly, but emails are not being sent because Gmail credentials are not configured in Vercel.

**Error in Vercel logs:**
```
Invalid login: 535-5.7.8 Username and Password not accepted
```

This means `GMAIL_USER` and `GMAIL_APP_PASSWORD` environment variables are either:
- Not set in Vercel
- Set incorrectly
- Using an invalid Gmail App Password

---

## ✅ Solution: Configure Gmail in Vercel (5 minutes)

### Step 1: Generate Gmail App Password

You need a **Gmail App Password** (not your regular Gmail password).

1. **Enable 2-Factor Authentication**:
- Go to: https://myaccount.google.com/security
- Enable "2-Step Verification" if not already enabled

2. **Generate App Password**:
- Go to: https://myaccount.google.com/apppasswords
- Select app: "Mail"
- Select device: "Other" → Enter "Wedding Website Vercel"
- Click "Generate"
- **Copy the 16-character password** (e.g., `abcd efgh ijkl mnop`)
- **Remove all spaces**: `abcdefghijklmnop`

### Step 2: Add Environment Variables in Vercel

1. Go to **Vercel Dashboard**: https://vercel.com/dashboard
2. Select your project
3. Go to **Settings** → **Environment Variables**
4. Add these variables for **Production** environment:

| Variable Name | Value |
|--------------|-------|
| `GMAIL_USER` | `codestromhub@gmail.com` |
| `GMAIL_APP_PASSWORD` | `abcdefghijklmnop` (your 16-char password, no spaces) |
| `GMAIL_FROM` | `Incia & Arvin Wedding <arvincia@sparrow-group.com>` |

5. Click **Save** for each variable

### Step 3: Redeploy

After adding environment variables, redeploy:

**Option A: Via Vercel Dashboard**
1. Go to "Deployments" tab
2. Click "..." on latest deployment → "Redeploy"

**Option B: Push to trigger deployment**
```bash
git commit --allow-empty -m "Trigger redeploy with Gmail credentials"
git push
```

### Step 4: Verify It Works

1. **Check Vercel Function Logs**:
- Go to Deployments → Latest → Functions
- Look for: `✅ [email] sent`

2. **Test the form**:
- Visit your Vercel site
- Submit contact form
- Check emails at:
- codestromhub@gmail.com
- arvincia@sparrow-group.com

---

## 🔍 Troubleshooting

### Still getting "Invalid login" error?

**Common causes:**
1. App Password has spaces (remove ALL spaces)
2. Using regular Gmail password instead of App Password
3. 2FA not enabled on Gmail
4. Wrong Gmail account used
5. Environment variables not saved properly

**Fix:**
1. Generate a **new** App Password
2. Remove ALL spaces from password
3. Update `GMAIL_APP_PASSWORD` in Vercel
4. Make sure you selected "Production" environment
5. Redeploy

### Emails still not sending?

**Check Vercel Function Logs** (this tells you exactly what's wrong):

| Log Message | Meaning | Solution |
|------------|---------|----------|
| `⚠️ GMAIL_USER or GMAIL_APP_PASSWORD is not set` | Env vars missing | Add them in Vercel Settings |
| `🔑 Gmail authentication failed` | Invalid credentials | Generate new App Password |
| `❌ Email error` | SMTP connection issue | Check Gmail account, 2FA enabled |
| `✅ [email] sent` | Success! | Emails should arrive |

### Database warnings (expected on Vercel)

You'll see warnings like:
```
Database save failed (expected in serverless), continuing with email
```

**This is normal!** SQLite doesn't work on Vercel (read-only file system). The code handles this gracefully:
- Database save is attempted but fails (expected)
- Email sending continues (this is what matters)
- User gets success message
- Forms work perfectly

---

## 📧 How Email System Works

```
User submits form
Vercel Serverless Function
Try to save to database (fails on Vercel, that's OK)
Send emails via Gmail SMTP
✓ To: arvincia@sparrow-group.com (primary)
✓ To: codestromhub@gmail.com (backup)
✓ Confirmation to user's email
Return success to user
```

**Key points:**
- Email sending is the primary functionality
- Database is optional (works on VPS, not on Vercel)
- Users always get emails even if database fails

---

## ✅ Success Checklist

- [ ] 2FA enabled on Gmail account
- [ ] Gmail App Password generated (16 characters, no spaces)
- [ ] `GMAIL_USER` added in Vercel (Production)
- [ ] `GMAIL_APP_PASSWORD` added in Vercel (Production)
- [ ] `GMAIL_FROM` added in Vercel (Production)
- [ ] Redeployed after adding environment variables
- [ ] Tested form submission
- [ ] Checked Vercel Function Logs
- [ ] Received test emails

---

## 🔒 Security Notes

1. **Never commit credentials to git** - Always use Vercel environment variables
2. **Use App Passwords only** - More secure than regular passwords
3. **Rotate periodically** - Generate new App Password every 6 months
4. **Monitor logs** - Check Vercel logs for suspicious activity

---

## 📞 Quick Reference

**Vercel Dashboard:** https://vercel.com/dashboard

**Generate App Password:** https://myaccount.google.com/apppasswords

**Environment Variables to Set:**
```
GMAIL_USER=codestromhub@gmail.com
GMAIL_APP_PASSWORD=your16charpassword # No spaces!
GMAIL_FROM=Incia & Arvin Wedding <arvincia@sparrow-group.com>
```

**After adding env vars:** Redeploy!

**Check logs:** Deployments → Latest → Functions → Look for ✅ or ❌

---

**Remember:** The forms work on Vercel, but emails won't send until you configure these Gmail credentials!
Binary file modified client/prisma/prisma/dev.db
Binary file not shown.
18 changes: 13 additions & 5 deletions client/src/app/api/contact/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,18 @@ export async function POST(request: NextRequest) {
const body = await request.json()
const validatedData = contactSchema.parse(body)

// Save contact request to database
const contactRequest = await prisma.contactRequest.create({
data: validatedData
})
// Try to save contact request to database (optional - for serverless environments)
let contactRequestId = 'email-only'
try {
const contactRequest = await prisma.contactRequest.create({
data: validatedData
})
contactRequestId = contactRequest.id
} catch (dbError) {
// Database might not be available in serverless environment (e.g., Vercel)
// Continue with email sending - this is the primary functionality
console.warn('Database save failed (expected in serverless), continuing with email:', dbError)
}

// Generate email content
const adminEmailHtml = generateContactNotificationEmail(
Expand Down Expand Up @@ -71,7 +79,7 @@ export async function POST(request: NextRequest) {

return NextResponse.json({
success: true,
id: contactRequest.id,
id: contactRequestId,
message: "Contact request submitted successfully"
})

Expand Down
52 changes: 30 additions & 22 deletions client/src/app/api/rsvp/form/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,35 @@ export async function POST(req: NextRequest) {
// Validate the data
const validatedData = rsvpFormSchema.parse(transformedData)

// Save to database
const rsvpSubmission = await prisma.rSVPFormSubmission.create({
data: {
guestName: validatedData.guestName,
email: validatedData.email,
willAttendDhaka: validatedData.willAttendDhaka,
familySide: validatedData.familySide,
guestCount: validatedData.guestCount,
guestCountOther: validatedData.guestCountOther,
additionalInfo: validatedData.additionalInfo,
preferredNumber: validatedData.preferredNumber,
preferredWhatsapp: validatedData.preferredWhatsapp || false,
preferredBotim: validatedData.preferredBotim || false,
secondaryNumber: validatedData.secondaryNumber,
secondaryWhatsapp: validatedData.secondaryWhatsapp || false,
secondaryBotim: validatedData.secondaryBotim || false,
emergencyName: validatedData.emergencyName,
emergencyPhone: validatedData.emergencyPhone,
emergencyEmail: validatedData.emergencyEmail,
},
})
// Try to save to database (optional - for serverless environments)
let rsvpSubmissionId = 'email-only'
try {
const rsvpSubmission = await prisma.rSVPFormSubmission.create({
data: {
guestName: validatedData.guestName,
email: validatedData.email,
willAttendDhaka: validatedData.willAttendDhaka,
familySide: validatedData.familySide,
guestCount: validatedData.guestCount,
guestCountOther: validatedData.guestCountOther,
additionalInfo: validatedData.additionalInfo,
preferredNumber: validatedData.preferredNumber,
preferredWhatsapp: validatedData.preferredWhatsapp || false,
preferredBotim: validatedData.preferredBotim || false,
secondaryNumber: validatedData.secondaryNumber,
secondaryWhatsapp: validatedData.secondaryWhatsapp || false,
secondaryBotim: validatedData.secondaryBotim || false,
emergencyName: validatedData.emergencyName,
emergencyPhone: validatedData.emergencyPhone,
emergencyEmail: validatedData.emergencyEmail,
},
})
rsvpSubmissionId = rsvpSubmission.id
} catch (dbError) {
// Database might not be available in serverless environment (e.g., Vercel)
// Continue with email sending - this is the primary functionality
console.warn('Database save failed (expected in serverless), continuing with email:', dbError)
}

const html = generateRSVPFormEmail(body)

Expand Down Expand Up @@ -98,7 +106,7 @@ export async function POST(req: NextRequest) {

return NextResponse.json({
success: true,
id: rsvpSubmission.id,
id: rsvpSubmissionId,
message: 'RSVP submitted successfully'
})
} catch (error) {
Expand Down
20 changes: 16 additions & 4 deletions client/src/lib/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ function getTransporter(): Transporter | null {
const pass = process.env.GMAIL_APP_PASSWORD

if (!user || !pass) {
console.warn('GMAIL_USER or GMAIL_APP_PASSWORD is not set. Skipping email send.')
console.warn('⚠️ GMAIL_USER or GMAIL_APP_PASSWORD is not set.')
console.warn('📧 Email sending will be skipped. Configure these environment variables in Vercel:')
console.warn(' - GMAIL_USER: Your Gmail email address')
console.warn(' - GMAIL_APP_PASSWORD: Gmail App Password (not regular password)')
console.warn(' Generate App Password at: https://myaccount.google.com/apppasswords')
return null
}

Expand All @@ -35,7 +39,8 @@ export async function sendEmail({ to, subject, html, from }: EmailData) {
try {
const tx = getTransporter()
if (!tx) {
return { success: false, error: new Error('Missing Gmail credentials') }
console.error('❌ Cannot send email - Gmail credentials not configured')
return { success: false, error: new Error('Missing Gmail credentials - configure GMAIL_USER and GMAIL_APP_PASSWORD in Vercel environment variables') }
}

const fromAddress =
Expand All @@ -49,11 +54,18 @@ export async function sendEmail({ to, subject, html, from }: EmailData) {
})) as SentMessageInfo
// Basic debug log for troubleshooting
try {
console.log('[email] sent', { messageId: info?.messageId as string | undefined, to })
console.log('[email] sent', { messageId: info?.messageId as string | undefined, to })
} catch {}
return { success: true, data: info }
} catch (error) {
console.error('Email error:', error)
console.error('❌ Email error:', error)
if (error instanceof Error && error.message.includes('Invalid login')) {
console.error('🔑 Gmail authentication failed. Check these in Vercel environment variables:')
console.error(' - GMAIL_USER is correct email address')
console.error(' - GMAIL_APP_PASSWORD is a valid Gmail App Password (not regular password)')
console.error(' - 2FA is enabled on Gmail account')
console.error(' Generate new App Password at: https://myaccount.google.com/apppasswords')
}
return { success: false, error }
}
}
Expand Down
Loading