Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
// Import express into our project
const express = require("express");
// Import multer
const multer = require("multer");
// Creating an instance of express function
const app = express();
// Import dotenv
require("dotenv").config();
// The port we want our project to run on
const PORT = 3000;
// Express should add our path -middleware
app.use(express.static("public"));
// Body parser
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
// Nodemailer
const nodemailer = require("nodemailer");
// FS
const fs = require("fs");
// Googleapis
const { google } = require("googleapis");
// Pull out OAuth from googleapis
const OAuth2 = google.auth.OAuth2;
// Multer file storage
const Storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, "./attachments");
},
filename: function (req, file, callback) {
callback(null, `${file.fieldname}_${Date.now()}_${file.originalname}`);
},
});
// Middleware to get attachments
const attachmentUpload = multer({
storage: Storage,
}).single("attachment");
const createTransporter = async () => {
//Connect to the oauth playground
const oauth2Client = new OAuth2(
process.env.OAUTH_CLIENT_ID,
process.env.OAUTH_CLIENT_SECRET,
"https://developers.google.com/oauthplayground"
);
// Add the refresh token to the Oauth2 connection
oauth2Client.setCredentials({
refresh_token: process.env.OAUTH_REFRESH_TOKEN,
});
const accessToken = await new Promise((resolve, reject) => {
oauth2Client.getAccessToken((err, token) => {
if (err) {
reject("Failed to create access token : error message(" + err);
}
resolve(token);
});
});
// Authenticating and creating a method to send a mail
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
type: "OAuth2",
user: process.env.SENDER_EMAIL,
accessToken,
clientId: process.env.OAUTH_CLIENT_ID,
clientSecret: process.env.OAUTH_CLIENT_SECRET,
refreshToken: process.env.OAUTH_REFRESH_TOKEN,
},
});
return transporter;
};
// Root directory -homepage
app.get("/", (req, res) => {
res.sendFile("/index.html");
});
// Route to handle sending mails
app.post("/send_email", (req, res) => {
attachmentUpload(req, res, async function (error) {
if (error) {
return res.send("Error uploading file");
} else {
// Pulling out the form data from the request body
const recipient = req.body.email;
const mailSubject = req.body.subject;
const mailBody = req.body.message;
const attachmentPath = req.file?.path;
// Mail options
let mailOptions = {
from: process.env.SENDER_EMAIL,
to: recipient,
subject: mailSubject,
text: mailBody,
attachments: [
{
path: attachmentPath,
},
],
};
try {
// Get response from the createTransport
let emailTransporter = await createTransporter();
// Send email
emailTransporter.sendMail(mailOptions, function (error, info) {
if (error) {
// failed block
console.log(error);
} else {
// Success block
console.log("Email sent: " + info.response);
// Delete file from the folder after sent
fs.unlink(attachmentPath, function (err) {
if (err) {
return res.end(err);
} else {
console.log(attachmentPath + " has been deleted");
return res.redirect("/success.html");
}
});
}
});
} catch (error) {
return console.log(error);
}
}
});
});
// Express allows us to listen to the port and trigger a console.log() when you visit the port
app.listen(PORT, () => {
console.log(`Server is currently 🏃‍♂️ on port ${PORT}`);
});
@alaomichael
Copy link

alaomichael commented Jun 23, 2021

Good day,
Thank you for the tutorial.
I think there is an error in line 102 ( const attachmentPath = req.file?.path; ).
I think the question mark should be removed.

Thanks once again and more grace to do more.

@unclebay143
Copy link
Author

unclebay143 commented Jun 28, 2021

Thanks for the feedback @alaomichael

The JS optional chaining operator (?) is an indication that the req.file can be null or undefined sometimes (because it is optional), that way javascript will not shout at us.

@harrydarwin
Copy link

harrydarwin commented Feb 19, 2022

I have copied an dpasted the code above and yet I get this error in the terminal
Failed to create access token : error message(Error: No refresh token or refresh handler callback is set.

@unclebay143
Copy link
Author

unclebay143 commented Feb 20, 2022

Hi @harrydarwin , did you forget to set up your environment variables?

@harrydarwin
Copy link

harrydarwin commented Feb 20, 2022

U got it @unclebay143 - I missed my own test email in the .env file - not sure if you included that.

thanks for your article, this was extremely useful/helpful.

@Taofeekfolami
Copy link

Taofeekfolami commented Feb 23, 2022

Nice tutorial. Quite detailed.

@unclebay143
Copy link
Author

unclebay143 commented Feb 24, 2022

Hi, @harrydarwin, glad to hear you found a fix, can you kindly tell me more about the test email in the .env file that you missed to know if I missed it in the tutorial article. Thanks

@unclebay143
Copy link
Author

unclebay143 commented Feb 24, 2022

@Taofeekfolami Thanks a lot for the feedback! Glad to hear this really.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment