Skip to content

Commit 70341f7

Browse files
committed
Move nodemailer usage to config/nodemailer; improve contact controller
1 parent 131a243 commit 70341f7

File tree

3 files changed

+94
-106
lines changed

3 files changed

+94
-106
lines changed

config/nodemailer.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const nodemailer = require('nodemailer');
2+
3+
/**
4+
* Helper Function to Send Mail.
5+
*/
6+
exports.sendMail = (settings) => {
7+
const transportConfig = {
8+
host: process.env.SMTP_HOST,
9+
port: 465,
10+
secure: true,
11+
auth: {
12+
user: process.env.SMTP_USER,
13+
pass: process.env.SMTP_PASSWORD
14+
}
15+
};
16+
17+
let transporter = nodemailer.createTransport(transportConfig);
18+
19+
return transporter.sendMail(settings.mailOptions)
20+
.then(() => {
21+
settings.req.flash(settings.successfulType, { msg: settings.successfulMsg });
22+
})
23+
.catch((err) => {
24+
if (err.message === 'self signed certificate in certificate chain') {
25+
console.log('WARNING: Self signed certificate in certificate chain. Retrying with the self signed certificate. Use a valid certificate if in production.');
26+
transportConfig.tls = transportConfig.tls || {};
27+
transportConfig.tls.rejectUnauthorized = false;
28+
transporter = nodemailer.createTransport(transportConfig);
29+
return transporter.sendMail(settings.mailOptions)
30+
.then(() => {
31+
settings.req.flash(settings.successfulType, { msg: settings.successfulMsg });
32+
})
33+
.catch((retryErr) => {
34+
console.log(settings.loggingError, retryErr);
35+
settings.req.flash(settings.errorType, { msg: settings.errorMsg });
36+
return retryErr;
37+
});
38+
}
39+
console.log(settings.loggingError, err);
40+
settings.req.flash(settings.errorType, { msg: settings.errorMsg });
41+
return err;
42+
});
43+
};

controllers/contact.js

Lines changed: 47 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
const axios = require('axios');
22
const validator = require('validator');
3-
const nodemailer = require('nodemailer');
3+
const nodemailerConfig = require('../config/nodemailer');
4+
5+
async function validateReCAPTCHA(token) {
6+
const response = await axios.post(`https://www.google.com/recaptcha/api/siteverify?secret=${process.env.RECAPTCHA_SECRET_KEY}&response=${token}`,
7+
{},
8+
{
9+
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' },
10+
});
11+
return response;
12+
}
413

514
/**
615
* GET /contact
@@ -20,7 +29,7 @@ exports.getContact = (req, res) => {
2029
* POST /contact
2130
* Send a contact form via Nodemailer.
2231
*/
23-
exports.postContact = async (req, res) => {
32+
exports.postContact = async (req, res, next) => {
2433
const validationErrors = [];
2534
let fromName;
2635
let fromEmail;
@@ -30,81 +39,54 @@ exports.postContact = async (req, res) => {
3039
}
3140
if (validator.isEmpty(req.body.message)) validationErrors.push({ msg: 'Please enter your message.' });
3241

33-
function getValidateReCAPTCHA(token) {
34-
return axios.post(`https://www.google.com/recaptcha/api/siteverify?secret=${process.env.RECAPTCHA_SECRET_KEY}&response=${token}`,
35-
{},
36-
{
37-
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' },
38-
});
39-
}
40-
4142
try {
42-
const validateReCAPTCHA = await getValidateReCAPTCHA(req.body['g-recaptcha-response']);
43-
if (!validateReCAPTCHA.data.success) {
43+
const reCAPTCHAResponse = await validateReCAPTCHA(req.body['g-recaptcha-response']);
44+
if (!reCAPTCHAResponse.data.success) {
4445
validationErrors.push({ msg: 'reCAPTCHA validation failed.' });
4546
}
47+
} catch (error) {
48+
console.error('Error validating reCAPTCHA:', error);
49+
validationErrors.push({ msg: 'Error validating reCAPTCHA. Please try again.' });
50+
}
4651

47-
if (validationErrors.length) {
48-
req.flash('errors', validationErrors);
49-
return res.redirect('/contact');
50-
}
51-
52-
if (!req.user) {
53-
fromName = req.body.name;
54-
fromEmail = req.body.email;
55-
} else {
56-
fromName = req.user.profile.name || '';
57-
fromEmail = req.user.email;
58-
}
59-
60-
const transportConfig = {
61-
host: process.env.SMTP_HOST,
62-
port: 465,
63-
secure: true,
64-
auth: {
65-
user: process.env.SMTP_USER,
66-
pass: process.env.SMTP_PASSWORD
67-
}
68-
};
52+
if (validationErrors.length) {
53+
req.flash('errors', validationErrors);
54+
return res.redirect('/contact');
55+
}
6956

70-
let transporter = nodemailer.createTransport(transportConfig);
57+
if (!req.user) {
58+
fromName = req.body.name;
59+
fromEmail = req.body.email;
60+
} else {
61+
fromName = req.user.profile.name || '';
62+
fromEmail = req.user.email;
63+
}
7164

65+
const sendContactEmail = async () => {
7266
const mailOptions = {
7367
to: process.env.SITE_CONTACT_EMAIL,
7468
from: `${fromName} <${fromEmail}>`,
7569
subject: 'Contact Form | Hackathon Starter',
7670
text: req.body.message
7771
};
7872

79-
return transporter.sendMail(mailOptions)
80-
.then(() => {
81-
req.flash('success', { msg: 'Email has been sent successfully!' });
82-
res.redirect('/contact');
83-
})
84-
.catch((err) => {
85-
if (err.message === 'self signed certificate in certificate chain') {
86-
console.log('WARNING: Self signed certificate in certificate chain. Retrying with the self signed certificate. Use a valid certificate if in production.');
87-
transportConfig.tls = transportConfig.tls || {};
88-
transportConfig.tls.rejectUnauthorized = false;
89-
transporter = nodemailer.createTransport(transportConfig);
90-
return transporter.sendMail(mailOptions);
91-
}
92-
console.log('ERROR: Could not send contact email after security downgrade.\n', err);
93-
req.flash('errors', { msg: 'Error sending the message. Please try again shortly.' });
94-
return false;
95-
})
96-
.then((result) => {
97-
if (result) {
98-
req.flash('success', { msg: 'Email has been sent successfully!' });
99-
return res.redirect('/contact');
100-
}
101-
})
102-
.catch((err) => {
103-
console.log('ERROR: Could not send contact email.\n', err);
104-
req.flash('errors', { msg: 'Error sending the message. Please try again shortly.' });
105-
return res.redirect('/contact');
106-
});
107-
} catch (err) {
108-
console.log(err);
73+
const mailSettings = {
74+
successfulType: 'info',
75+
successfulMsg: 'Email has been sent successfully!',
76+
loggingError: 'ERROR: Could not send contact email after security downgrade.\n',
77+
errorType: 'errors',
78+
errorMsg: 'Error sending the message. Please try again shortly.',
79+
mailOptions,
80+
req
81+
};
82+
83+
return nodemailerConfig.sendMail(mailSettings);
84+
};
85+
86+
try {
87+
await sendContactEmail();
88+
res.redirect('/contact');
89+
} catch (error) {
90+
next(error);
10991
}
11092
};

controllers/user.js

Lines changed: 4 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,15 @@
11
const { promisify } = require('util');
22
const crypto = require('crypto');
3-
const nodemailer = require('nodemailer');
43
const passport = require('passport');
54
const _ = require('lodash');
65
const validator = require('validator');
76
const mailChecker = require('mailchecker');
87
const User = require('../models/User');
98
const Session = require('../models/Session');
9+
const nodemailerConfig = require('../config/nodemailer');
1010

1111
const randomBytesAsync = promisify(crypto.randomBytes);
1212

13-
/**
14-
* Helper Function to Send Mail.
15-
*/
16-
const sendMail = (settings) => {
17-
const transportConfig = {
18-
host: process.env.SMTP_HOST,
19-
port: 465,
20-
secure: true,
21-
auth: {
22-
user: process.env.SMTP_USER,
23-
pass: process.env.SMTP_PASSWORD
24-
}
25-
};
26-
27-
let transporter = nodemailer.createTransport(transportConfig);
28-
29-
return transporter.sendMail(settings.mailOptions)
30-
.then(() => {
31-
settings.req.flash(settings.successfulType, { msg: settings.successfulMsg });
32-
})
33-
.catch((err) => {
34-
if (err.message === 'self signed certificate in certificate chain') {
35-
console.log('WARNING: Self signed certificate in certificate chain. Retrying with the self signed certificate. Use a valid certificate if in production.');
36-
transportConfig.tls = transportConfig.tls || {};
37-
transportConfig.tls.rejectUnauthorized = false;
38-
transporter = nodemailer.createTransport(transportConfig);
39-
return transporter.sendMail(settings.mailOptions)
40-
.then(() => {
41-
settings.req.flash(settings.successfulType, { msg: settings.successfulMsg });
42-
});
43-
}
44-
console.log(settings.loggingError, err);
45-
settings.req.flash(settings.errorType, { msg: settings.errorMsg });
46-
return err;
47-
});
48-
};
49-
5013
/**
5114
* GET /login
5215
* Login page.
@@ -398,7 +361,7 @@ exports.getVerifyEmail = (req, res, next) => {
398361
mailOptions,
399362
req
400363
};
401-
return sendMail(mailSettings);
364+
return nodemailerConfig.sendMail(mailSettings);
402365
};
403366

404367
createRandomToken
@@ -460,7 +423,7 @@ exports.postReset = (req, res, next) => {
460423
mailOptions,
461424
req
462425
};
463-
return sendMail(mailSettings);
426+
return nodemailerConfig.sendMail(mailSettings);
464427
};
465428

466429
resetPassword()
@@ -534,7 +497,7 @@ exports.postForgot = (req, res, next) => {
534497
mailOptions,
535498
req
536499
};
537-
return sendMail(mailSettings);
500+
return nodemailerConfig.sendMail(mailSettings);
538501
};
539502

540503
createRandomToken

0 commit comments

Comments
 (0)