From 30292c28c1f3079c391ab91c540bcfa008d6669c Mon Sep 17 00:00:00 2001 From: Caner <s86215@bht-berlin.de> Date: Fri, 30 Jun 2023 23:35:55 +0200 Subject: [PATCH] nodemailer setup --- app/api/email/route.ts | 51 ++++++++++++++++++++++++++++ components/user-auth-form.tsx | 26 +++++++++++++++ lib/auth.ts | 4 +++ lib/config/nodemailer.ts | 62 +++++++++++++++++++++++++++++++++++ package-lock.json | 19 +++++++++++ package.json | 4 ++- 6 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 app/api/email/route.ts create mode 100644 lib/config/nodemailer.ts diff --git a/app/api/email/route.ts b/app/api/email/route.ts new file mode 100644 index 0000000..db67cc8 --- /dev/null +++ b/app/api/email/route.ts @@ -0,0 +1,51 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; +import * as nodemailer from 'nodemailer'; + +// Nodemailer docs: // https://nodemailer.com/about/ +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + // https://nodemailer.com/smtp/ + const transporter = nodemailer.createTransport({ + service: "gmail", + auth: { + user: process.env.NODEMAIL_MAIL, + pass: process.env.NODEMAIL_PW, + }, + secure: false, // Default value but showing for explicitness + }); + + const { subject, email, html } = req.body; + + if (!subject || !email || !html) { + return res + .status(400) + .json({ message: 'Please fill out the necessary fields' }); + } + + // https://nodemailer.com/message/#common-fields + const mailData = { + from: email, + to: email, + subject: `${subject}`, + text: `${subject} | Sent from: ${email}`, + html: `${html}`, + }; + + await new Promise((resolve, reject) => { + transporter.sendMail(mailData, (err: Error | null, info) => { + if (err) { + reject(err); + return res + .status(500) + .json({ error: err.message || 'Something went wrong' }); + } else { + resolve(info.accepted); + res.status(200).json({ message: 'Message sent!' }); + } + }); + }); + + return; +} \ No newline at end of file diff --git a/components/user-auth-form.tsx b/components/user-auth-form.tsx index f956d48..4101b47 100644 --- a/components/user-auth-form.tsx +++ b/components/user-auth-form.tsx @@ -95,6 +95,32 @@ export function UserAuthForm({ type, className, ...props }: UserAuthFormProps) { action: <ToastAction altText="Try again">Try again</ToastAction>, }) } + try { + const res = await fetch('/api/email', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify( + subject: "Test", + email: data.email, + + + ), + }); + + const body = await res.json(); + + if (res.ok) { + alert(`${body.message} 🚀`); + } + + if (res.status === 400) { + alert(`${body.message} 😢`); + } + } catch (err) { + console.log('Something went wrong: ', err); + } router.push("/home") diff --git a/lib/auth.ts b/lib/auth.ts index b1696bb..6834734 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -55,6 +55,10 @@ export const authOptions: NextAuthOptions = { throw new Error('invalid password') } + if(!user.emailVerified){ + throw new Error('email not verifyed') + } + return { id: user.id, username: user.username, diff --git a/lib/config/nodemailer.ts b/lib/config/nodemailer.ts new file mode 100644 index 0000000..7ec015f --- /dev/null +++ b/lib/config/nodemailer.ts @@ -0,0 +1,62 @@ + +import * as nodemailer from "nodemailer"; +import { MailOptions } from "nodemailer/lib/json-transport"; + +export class Emailer { + private readonly transporter: nodemailer.Transporter; + + constructor() { + this.transporter = nodemailer.createTransport({ + service: "gmail", + auth: { + user: process.env.NODEMAIL_MAIL, + pass: process.env.NODEMAIL_PW, + }, + }); + } + + public sendEmail(mailOptions: MailOptions) { + return this.transporter.sendMail(mailOptions); + } + + public notifyAdminForNewUser(email: string, username: string) { + this.sendEmail(notifyAdminNewUserEmailTemplate(email, username)); + } + + public notifyUserForSignup(email: string, username: string) { + this.sendEmail(newUserEmailTemplate(email, username)); + } +} + +export const emailer = new Emailer(); + +export const newUserEmailTemplate = (email: string, username: string) => { + return { + from: process.env.GMAIL_USER, + to: email, + subject: `${username}, Welcome to the our website`, + text: "Welcome to the our website", + html: ` + <h1>Welcome to our website!</h1> + <p>We're glad you've decided to join us. We hope you find everything you're looking for here and enjoy using our site.</p> + <p>If you have any questions or need any help, please don't hesitate to contact us. Thank you for signing up!</p> + `, + } as MailOptions; +}; + +export const notifyAdminNewUserEmailTemplate = ( + email: string, + username: string +) => { + return { + from: process.env.GMAIL_USER, + to: process.env.GMAIL_USER, + subject: `New User: ${username} - email: ${email}`, + text: `New User: ${username} - email: ${email}`, + html: ` + <h1>New User: ${username}</h1> + <p>email: ${email}</p> + `, + } as MailOptions; +}; + diff --git a/package-lock.json b/package-lock.json index cc3d3ed..0e5e3d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "next": "^13.4.7", "next-auth": "^4.22.1", "next-themes": "^0.2.1", + "nodemailer": "^6.9.3", "normalize-diacritics": "^4.0.0", "react": "18.2.0", "react-dom": "18.2.0", @@ -52,6 +53,7 @@ "@types/bcrypt": "^5.0.0", "@types/jest": "^29.5.2", "@types/node": "^20.3.2", + "@types/nodemailer": "^6.4.8", "@types/react": "^18.2.14", "@types/react-dom": "^18.2.6", "autoprefixer": "10.4.14", @@ -2859,6 +2861,15 @@ "integrity": "sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==", "dev": true }, + "node_modules/@types/nodemailer": { + "version": "6.4.8", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.8.tgz", + "integrity": "sha512-oVsJSCkqViCn8/pEu2hfjwVO+Gb3e+eTWjg3PcjeFKRItfKpKwHphQqbYmPQrlMk+op7pNNWPbsJIEthpFN/OQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/prettier": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", @@ -8087,6 +8098,14 @@ "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", "dev": true }, + "node_modules/nodemailer": { + "version": "6.9.3", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.3.tgz", + "integrity": "sha512-fy9v3NgTzBngrMFkDsKEj0r02U7jm6XfC3b52eoNV+GCrGj+s8pt5OqhiJdWKuw51zCTdiNR/IUD1z33LIIGpg==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", diff --git a/package.json b/package.json index f87a373..277e19b 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "next": "^13.4.7", "next-auth": "^4.22.1", "next-themes": "^0.2.1", + "nodemailer": "^6.9.3", "normalize-diacritics": "^4.0.0", "react": "18.2.0", "react-dom": "18.2.0", @@ -58,6 +59,7 @@ "@types/bcrypt": "^5.0.0", "@types/jest": "^29.5.2", "@types/node": "^20.3.2", + "@types/nodemailer": "^6.4.8", "@types/react": "^18.2.14", "@types/react-dom": "^18.2.6", "autoprefixer": "10.4.14", @@ -70,4 +72,4 @@ "tailwindcss": "3.3.2", "typescript": "^5.1.6" } -} \ No newline at end of file +} -- GitLab