diff --git a/backend/package.json b/backend/package.json index 2f4e899..e33543c 100644 --- a/backend/package.json +++ b/backend/package.json @@ -14,7 +14,8 @@ "cors": "^2.8.5", "dotenv": "^16.3.1", "sqlite3": "^5.1.6", - "sqlite": "^4.1.2" + "sqlite": "^4.1.2", + "nodemailer": "^6.9.8" }, "devDependencies": { "@types/express": "^4.17.17", diff --git a/backend/src/email.ts b/backend/src/email.ts new file mode 100644 index 0000000..2648c71 --- /dev/null +++ b/backend/src/email.ts @@ -0,0 +1,63 @@ +import nodemailer from 'nodemailer'; + +const transporter = nodemailer.createTransport({ + host: process.env.EMAIL_HOST, + port: Number(process.env.EMAIL_PORT), + secure: process.env.EMAIL_SECURE === 'true', // true for 465, false for other ports + auth: { + user: process.env.EMAIL_USER, + pass: process.env.EMAIL_PASS, + }, +}); + +export interface RSVPEmailData { + eventTitle: string; + name: string; + attending: string; + bringingGuests: string; + guestCount: number; + guestNames: string[]; + itemsBringing: string[]; + otherItems: string; + to: string; +} + +export async function sendRSVPEmail(data: RSVPEmailData) { + const { + eventTitle, + name, + attending, + bringingGuests, + guestCount, + guestNames, + itemsBringing, + otherItems, + to, + } = data; + + const subject = `RSVP Confirmation for ${eventTitle}`; + const guestList = guestNames.length ? guestNames.join(', ') : 'None'; + const itemsList = itemsBringing.length ? itemsBringing.join(', ') : 'None'; + const otherItemsList = otherItems ? otherItems : 'None'; + + const html = ` +
Event: ${eventTitle}
+Name: ${name}
+Attending: ${attending}
+Bringing Guests: ${bringingGuests} (${guestCount})
+Guest Names: ${guestList}
+Items Bringing (from needed list): ${itemsList}
+Other Items: ${otherItemsList}
+ `; + + await transporter.sendMail({ + from: { + name: process.env.EMAIL_FROM_NAME || '', + address: process.env.EMAIL_FROM_ADDRESS || process.env.EMAIL_USER || '', + }, + to, + subject, + html, + }); +} \ No newline at end of file diff --git a/backend/src/index.ts b/backend/src/index.ts index 8ea0d2e..7993c5d 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -6,6 +6,7 @@ import dotenv from 'dotenv'; import path from 'path'; import multer from 'multer'; import fs from 'fs'; +import { sendRSVPEmail } from './email'; dotenv.config(); @@ -294,6 +295,29 @@ app.post('/api/events/:slug/rsvp', async (req: Request, res: Response) => { [eventId, name, attending, bringing_guests, guest_count, JSON.stringify(parsedGuestNames), JSON.stringify(parsedItemsBringing), other_items || ''] ); + // Fetch event title for the email + const eventInfo = await db.get('SELECT title FROM events WHERE id = ?', [eventId]); + const eventTitle = eventInfo ? eventInfo.title : slug; + + // Send RSVP confirmation email (if email provided) + if (req.body.email) { + try { + await sendRSVPEmail({ + eventTitle, + name, + attending, + bringingGuests: bringing_guests, + guestCount: guest_count, + guestNames: parsedGuestNames, + itemsBringing: parsedItemsBringing, + otherItems: other_items || '', + to: req.body.email, + }); + } catch (emailErr) { + console.error('Error sending RSVP email:', emailErr); + } + } + // Return the complete RSVP data including the parsed arrays res.status(201).json({ id: result.lastID, diff --git a/docker-compose.yml b/docker-compose.yml index f600924..222d0c8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,6 +9,13 @@ services: - uploads:/app/uploads environment: - NODE_ENV=production + - EMAIL_HOST=smtp.example.com + - EMAIL_PORT=587 + - EMAIL_USER=your@email.com + - EMAIL_PASS=yourpassword + - EMAIL_FROM_NAME=RSVP Manager + - EMAIL_FROM_ADDRESS=your@email.com + - EMAIL_SECURE=false restart: unless-stopped volumes: