Nodemailer not giving error if email not sent - javascript

I'm trying to use nodemailer to send emails. But if the "to" field has wrong email address then the email is not sent, which is right. But it does not give me an error and the function gets resolved.
Below is my code:
const send = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 1234,
secure: false,
type: 'login',
auth: {
user: USER,
pass: PASSWORD
}
})
let message = {
from: 'some email',
to: 'johndoe#gmai.c',
subject: 'subject',
html: html
}
return new Promise((resolve: any, reject: any) => {
send.sendMail(message, (error: any, result: any) => {
if (error){
console.log('Error')
reject(error)
return
}
resolve(result)
})
})
I'm using typescript btw. Never logs the error if the email is not sent or the "to" field has the wrong email. Any suggestions?

I don't think you can catch the error if the email is wrong but you can firstly check if the email is a valid string using regex before sending an email. So, if you get emails like johndoe#gmai.c. You can prevent sending wrong emails. This will not help in detecting if the email is correct or incorrect but at least it will ensure a correct email format which will decrease the no. of unwanted emails sent.
Using vanilla JavaScript - but can easily be converted into Typescript as there is not much complexity
try {
let to = "johndoe#gmai.c";
let validEmail = validateEmail(to);
if (validEmail) {
let info = transporter.sendMail({
from: 'some.email'
to: to,
subject: "Hello",
text: "Hello world?",
html: "<b>Hello world?</b>",
});
console.log("Message sent: ", info.messageId);
} else {
throw "Email Not Valid";
}
} catch (e) {
console.log("Error Occurred: ", e);
}
//A function to check if email is valid using regex
function validateEmail(email) {
const re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]
{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
}

Related

How can I validate this in more elegant way?

Im trying to do login/register module in my project. This is my login function. I would like to have one function that will validate all things for me so I dont have to use so many "if" statements. I was trying to do with pure function but completely don't know how to do it. Can someone help me ?
const loginUser = async (req, res, next) => {
const { password, email } = req.body;
if (!email) {
return res.status(400).json({
message: "Error: Email cannot be blank.",
});
}
if (!password) {
return res.status(400).json({
message: "Error: Password cannot be blank.",
});
}
try {
const user = await User.findOne({ email: email });
if (!user)
return res.status(400).json({
message: "Invalid user",
});
if (!validPassword(password, user.password))
return res.status(400).json({
message: "Invalid password",
});
const { name, likedArr, _id } = user;
const token = crypto.randomBytes(32).toString("hex");
const userSession = new UserSession({ userId: _id, token });
await userSession.save();
return res.status(200).json({
message: "Valid login",
token: token,
user: {
name,
likedArr,
userId: _id,
},
});
} catch (err) {
next(err);
}
};
Abstracting my comments into an answer.
On Pure Functions:
If I understand pure functions correctly, I don't think you can have a pure function that calls an external API which may fail, since the same inputs may possibly return different results depending on the external state of the API (unless that API is guaranteed pure itself somehow). (Definition of a pure function)
On Repetition:
I genuinely think you don't have a lot of repetition here. Your code is clear and only has 4 conditionals, all for things you need to test for. You could abstract the similarities of your JSON returns into something like a template string depending on the conditions, but I think that could add clutter and opacity to your code, which isn't a good trade-off if you do it too much.
If you want an example of what I mean here:
if (!email) {
return res.status(400).json({
message: "Error: Email cannot be blank.",
});
}
if (!password) {
return res.status(400).json({
message: "Error: Password cannot be blank.",
});
}
Can become...
if (!email || !password) {
return res.status(400).json({
message: `Error: ${!email ? 'Email' : 'Password'} cannot be blank.`,
});
}

Nodemailer: No recipients Defined, how to fix?

When trying to send data from a form on a react.js component I am getting this error when I push the submit button to send the data to an e-mail address:
Error: No recipients defined
Can anyone tell me how I can fix this issue to get the data sending to an e-mail address I want?
Here is my mail.js file code:
const { Email } = require("./email_template");
const getEmailData = (template) => {
let data = null;
switch (template) {
case "hello":
data = {
from: "Contact Form",
to: "matthew.devonport.test#gmail.com",
subject: `Message from the contact form!`,
html: Email()
}
break;
default:
data;
}
return data;
}
const sendEmail = (to, name, type) => {
const smtpTransport = mailer.createTransport({
service: "Gmail",
auth: {
user: "testemail#gmail.com",
pass: "testpass"
}
})
const mail = getEmailData(to, name, type)
smtpTransport.sendMail(mail, function(error, response) {
if(error) {
console.log(error)
} else {
alert( "Thank you! We will be in touch shortly!")
}
smtpTransport.close();
})
}
module.exports = { sendEmail }```
Check your input to your function:
getEmailData(template)
When you invoke the method in sendEmail you don't match the input parameters
const mail = getEmailData(to, name, type)
Which returns null and gives the error implying on missing data.

Why can't I send to more than one address using AWS SDK sendEmail?

I started implementing the AWS SDK into our application to send emails. I increased our limit through AWS to get out of the sandbox so that I could start sending emails to other people. The problem I'm noticing is that if I have more than one address in my recipient variable that I get this error: Illegal Address. Both email addresses are in the form name#domain.com. I've tested sending to each email individually and both work just fine, but as soon as I put both addresses into the recipient variable I get the Illegal Address error. My only assumption is that having more than one recipient is causing the issue, but if this is the problem then why does their documentation say that there can be multiple addresses included?
Here is my code
if ((request.url).substring(0, 5) == "/send") {
var mailOptions = {
to: request.query.to,
bcc: request.query.bcc,
subject: request.query.subject,
text: request.query.text
}
console.log(mailOptions.to);
AWS.config.update({
accessKeyId: env.AWS.ACCESS_KEY,
secretAccessKey: env.AWS.SECRET_ACCESS_KEY,
region: 'someregion'
});
const sender = "noreply#domain.com";
const recipient = mailOptions.to; // this includes "name#domain.com, name2#domain.com"
const subject = mailOptions.subject;
const body_html = mailOptions.text;
const charset = "UTF-8";
const ses = new AWS.SES();
var params = {
Source: sender,
Destination: {
ToAddresses: [
recipient
],
BccAddresses: [
sender
],
},
Message: {
Subject: {
Data: subject,
Charset: charset
},
Body: {
Html: {
Data: body_html,
Charset: charset
}
}
}
};
ses.sendEmail(params, function(err, data) {
// If something goes wrong, print an error message.
if(err) {
console.log(err.message);
} else {
console.log("Email sent! Message ID: ", data.MessageId);
}
});
If anyone knows why this is happening and knows what I need to do to fix it, I would greatly appreciate it! Thanks.

How to reset password of AWS Cognito user?

If I click the "reset password" button for a user in the AWS Cognito, all it does is re-send the verification email, containing the account registration email code.
However, if the user takes that code and enters it on the verification page, AWS returns the error:
NotAuthorizedException: User cannot be confirmed. Current status is RESET_REQUIRED
First, how do I get Cognito to send a real "password reset" email instead of the "confirm your registration" email?
I assume it's giving me this error because the verification JS is calling:
createCognitoUser(email).confirmRegistration(code, true, function confirmCallback(err, result)
and not some undocumented password reset function. What function should I be calling?
You should be calling forgotPassword. From the AWS Documentation at Using Amazon Cognito User Identity Pools Javascript Examples:
cognitoUser.forgotPassword({
onSuccess: function (result) {
console.log('call result: ' + result);
},
onFailure: function(err) {
alert(err);
},
inputVerificationCode() {
var verificationCode = prompt('Please input verification code ' ,'');
var newPassword = prompt('Enter new password ' ,'');
cognitoUser.confirmPassword(verificationCode, newPassword, this);
}
});
So Even I faced a same issue, Even in AWS cognito documentation it was not clear, basically the process involves two steps.
call cognitoUser.forgotPassword() this will start forgot password process flow, and the user will receive a verification code.
then call cognitoUser.confirmPassword() which will reset the password verifying the code send to the email of user.
Below I have given a cognitoUserClass which has static methods forgotPassword() and confirmPassword() methods which implements those two steps.
import * as AmazonCognitoIdentity from 'amazon-cognito-identity-js'
class cognitoUserClass {
static cognitouser: AmazonCognitoIdentity.CognitoUser
static userPool = new AmazonCognitoIdentity.CognitoUserPool({
UserPoolId: 'your pool id',
ClientId: 'your client id',
})
static forgotPassword(userName: string): void {
const userData = {
Username: userName,
Pool: cognitoUserClass.userPool,
}
cognitoUserClass.cognitouser = new AmazonCognitoIdentity.CognitoUser(
userData
)
cognitoUserClass.cognitouser.forgotPassword({
onSuccess: (data) => {
console.log(data)
},
onFailure: (err) => {
console.log('ERR:', err)
},
})
}
static confirmPassword(
verificationCode: string,
newPassword: string
): void {
cognitoUserClass.cognitouser.confirmPassword(
verificationCode,
newPassword,
{
onFailure(err) {
console.log(err)
},
onSuccess(data) {
console.log(data)
},
}
)
}
}
export { cognitoUserClass }

feathersjs: How do I pass un-opinionated errors back to client

Seems like error messages are wrapped in text. Say in a model validation I just want to send "exists" to the client if a record already exists.
One the server maybe I do something like:
validate: {
isEmail: true,
isUnique: function (email, done) {
console.log("checking to see if %s exists", email);
user.findOne({ where: { email: email }})
.then(function (user) {
done(new Error("exists"));
},function(err) {
console.error(err);
done(new Error('ERROR: see server log for details'));
}
);
}
}
On the client maybe I do:
feathers.service('users').create({
email: email,
password: password
})
.then(function() {
console.log("created");
})
.catch(function(error){
console.error('Error Creating User!');
console.log(error);
});
The error printed to console is:
"Error: Validation error: exists"
How to I just send the word "exists" without the extra text? Really I'd like to send back a custom object, but I can't seem to find any examples of doing this. The closest I've seen is this: https://docs.feathersjs.com/middleware/error-handling.html#featherserror-api
But I haven't figured out how to make something like this work in the validator.
Feathers does not change any error messages so the Validation error: prefix is probably added by Mongoose.
If you want to change the message or send an entirely new error object, as of feathers-hooks v1.6.0 you can use error hooks:
const errors = require('feathers-errors');
app.service('myservice').hooks({
error(hook) {
const { error } = hook;
if(error.message.indexOf('Validation error:') !== -1) {
hook.error = new errors.BadRequest('Something is wrong');
}
}
});
You can read more about error and application hooks here

Categories