AWS SES from NodeJS not DKIM signed? - node.js

I am using nodemailer to send emails using SES
const nodemailer = require('nodemailer')
const sesTransport = require('nodemailer-ses-transport')
const transporter = nodemailer.createTransport(sesTransport({
accessKeyId: '...',
secretAccessKey: '...',
region: 'us-east-1'
}))
When I try to send test emails from AWS SES Dashboard, it works. But when I send via code, it goes into spam. I've already followed the steps to "enable easy DKIM" http://docs.aws.amazon.com/ses/latest/DeveloperGuide/easy-dkim.html. When I check the verification status of DKIM on AWS Dashboard, its verified. Do I need to explicitly sign emails when sending via code? In the example from https://nodemailer.com/dkim/, I need a private key. Which private key isit? Where do I get it? Also what values do I put into domainName and keySelector?
let transporter = nodemailer.createTransport({
service: 'Gmail',
dkim: {
domainName: 'example.com',
keySelector: '2017',
privateKey: '-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBg...'
}
});

Ok so I can close this. It appears nodemailer didnt correctly sign emails using DKIM. Using AWS SDK directly and calling setIdentityDkimEnabled to enable DKIM fixes things.

Related

Unable to use SendInBlue with Gmail and Nodemailer Properly

Before I go into this, I know two very common issues with Gmail with Nodemailer is that Allow Less Secure Apps is disabled by default, and I know two factor authentication can provide similar issues. Neither of these is the case.
I am attempting to make a system wherein many user accounts can be created en masse. When they are created, each account will receive an email with a greeting and their password. The issue was that gmail does not like spam, so the emails wouldn't send. I tried adding a 1 second wait period between each mutation thus between each email, but that didn't work either.
I now have a SendInBlue Account, using that same gmail. My code looks like this now...
////////////////////////////////
/// ///
/// EMAIL STUFF ///
/// ///
////////////////////////////////
// Creates the Transporter
const transporter = nodemailer.createTransport({
service: "SendinBlue",
auth: {
user: `${process.env.EMAIL_ADDRESS}`,
pass: `${process.env.EMAIL_PASSWORD}`
}
})
// Creates the Mail Object
const mailOptions = {
from: `${process.env.EMAIL_ADDRESS}`,
to: `${actualEmail}`,
subject: `Thank you for joining the TOM Team!`,
text: `We have recieved your Account Signup and are please to welcome you to the TOM Experience!`
}
// Sends the mail
transporter.sendMail(mailOptions, (error, response) => {
if (error){
throw new Error('Something went wrong, please try again \n' + error)
}
})
Wherein the only thing in the code above that is different than when it was sending (or at least it was trying to send before it got hit with the spam block) is the line service: "SendinBlue", was changed from service: "Gmail",
Is this an issue with SendInBlue, or does this look more like a Gmail / Nodemailer issue? Could anyone assist

Can I use any email under my domain name to send emails using AWS SES?

Pardon me if I am asking a pretty dumb question. I am new to SES and I could not find a straight answer in the AWS docs about this.
Some background info: I am using node server on EC2. I own a domain, let's say "mydomain.com". I only need AWS SES to send out emails to my customers and I plan to use AWS-SDK in my EC2 server to talk to SES. I do not need to receive any emails from customers.
According to AWS SES docs, I only need to verify either my domain OR my email address - just one of them.
Let's say I choose to verify my domain, mydomain.com, and I did not verify email. So, when I use AWS-SDK sendEmail(), what email should/can I use given that I did not verify any email?
Can I use any email as long as it is using my domain name? E.g. support#mydomain.com?
Thank you for your answer!
The verification is there to make sure you are the owner of the domain or at least an email address you want to use.
So when you verify the domain you are verified as the admin of the domain and thus have access to any of the email address on that specific domain.
To elaborate, if you can prove that you can change the DNS records of the domain (as you did for the verification) you can change any email related DNS records such as the MX records (more on the wiki) and thus any additional verification is not necessary.
I encourage you to learn more about the MX records.
As long as you are able to verify your domain, yes you can use any email with your domain name. AWS wants to know you are the owner of the domain.
Tip regarding:
"I plan to use AWS-SDK in my EC2 server to talk to SES."
I would recommend to use AWS Lambda function using NodeJS and trigger them from the API gateway. This way you will save money spent on monthly EC2 instances with highly available API to send out emails.
Additionally you can then use this API anywhere in your business process flows.
Here is a sample code to send out emails using AWS SES service via Lambda function.
var AWS = require('aws-sdk');
var ses = new AWS.SES();
var RECEIVER = 'to#yourdomain.com';
var SENDER = 'from#yourdomain.com';
var response = {
"isBase64Encoded": false,
"statusCode": 200,
"headers": {
"X-Requested-With": '*',
"Access-Control-Allow-Headers": 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,x-requested-with',
"Access-Control-Allow-Origin": '*',
"Access-Control-Allow-Methods": 'POST,GET,OPTIONS'
},
"body": "{\"result\": \"Success.\"}"
};
exports.handler = function (event, context) {
var formdata = JSON.parse(event.body);
sendEmail(formdata, function (err, data) {
context.done(err, response);
});
};
function sendEmail (formdata, done) {
var params = {
Destination: {
ToAddresses: [
RECEIVER
]
},
Message: {
Body: {
Text: {
Data: 'name: ' + formdata.name + '\nemail: ' + formdata.email + '\ndesc: ' + formdata.desc,
Charset: 'UTF-8'
}
},
Subject: {
Data: 'Website Referral Form: ' + formdata.name,
Charset: 'UTF-8'
}
},
Source: SENDER
};
ses.sendEmail(params, done);
}

Nodemailer with ZOHO mail

I'm trying to setup ZOHO mail with Nodemailer. The mail is configured correctly and I'm using following code to send the mail:
var transporter = nodemailer.createTransport({
host: 'smtp.zoho.eu',
port: 465,
secure: true, //ssl
auth: {
user:'info#myaddress.be',
pass:'supersecretpassword'
}
});
sendMail = function(req,res) {
var data = req.body;
transporter.sendMail({
from: data.contactEmail,
to: 'info#myaddress.be',
subject: data.contactSubject,
text: data.contactMsg
});
res.json(data);
};
I contacted official support but no response so far. Maybe someone here has experience with it. The problem is that when using these settings I get a message that relaying is disallowed for the address in variable 'data.contactEmail'. When I change the from e-mail also to info#myaddress.be I do receive the e-mail but of course I do not know who sent it and can't reply to it.
Anyone who knows how to make the 'from' address work with unknown addresses? Like john#gmail.com ?
Solution :
You should make an email account for your server : bot#myaddress.be
When you are going to relay the mail craft a custom MAILBODY containing the subject and message
var MAILBODY ='\n[suject]:\n'+data.contactSubject+'\n\n[msg]:\n'+data.contactMsg;
So you will be sending the original contactEmail as the subject of the mail and using the mail's text (body) to se the message subject and the message content.
transporter.sendMail({
from: 'bot#myaddress.be',
to: 'info#myaddress.be',
subject: data.contactEmail,
text: MAILBODY
});
Reason of Solution :
Example bot account will be able of sending the email to yourself with all the details you really need. (because you control that email account / your domain)
The credentials you are providing are for your OWN account and you are trying to send an email FROM an unknown account. This might only be possible if you had the credentials for the unknown account (given that they have allowed open access to other clients/apps).
You simply can not send an email on behalf of an account you do not have credentials for.

Username and Password not accepted when using nodemailer?

This is my settingController:
var sendSmtpMail = function (req,res) {
var transport = nodemailer.createTransport({
service:'gmail',
auth: {
user: "asdfqweerrccb#limitlesscircle.com",
pass: "qwerr#wee"
}
});
var mailOptions = {
from: "transactions#limitlesscircle.com",
to:'umaraja1124#gmail.com',
subject: req.body.subject+"nodejs working ?",
text: "Hello world ?",
}
transport.sendMail(mailOptions, function(error, response){
if(error){
res.send("Email could not sent due to error: "+error);
console.log('Error');
}else{
res.send("Email has been sent successfully");
console.log('mail sent');
}
});
in postman I got the error like that:
Email could not sent due to error:
Error: Invalid login: 535-5.7.8 Username and Password not accepted. Learn more at 535 5.7.8 https://support.google.com/mail/?p=BadCredentials g7sm64435626pfj.29 - gsmtp
Update (2022-05-02)
As mentioned in the comments and directly quoted from Google:
On May 30 2022, you may lose access to apps that are using less secure
sign-in technology
So the bottom code will probably stop working with Gmail. The solution is to enable 2-Step Verification and generate Application password, then you can use the generated password to send emails using nodemailer.To do so you need to do the following:
Go to your Google account at https://myaccount.google.com/
Go to Security
In "Signing in to Google" section choose 2-Step Verification - here you have to verify yourself, in my case it was with phone number and a confirmation code send as text message. After that you will be able to enabled 2-Step Verification
Back to Security in "Signing in to Google" section choose App passwords
From the Select app drop down choose Other (Custom name) and put a name e.g. nodemailer
A modal dialog will appear with the password. Get that password and use it in your code.
If there is still a problem, try clearing captcha by visiting https://accounts.google.com/DisplayUnlockCaptcha from your Google account.
Sample usege
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'YOUR-USERNAME',
pass: 'THE-GENERATED-APP-PASSWORD'
}
});
send();
async function send() {
const result = await transporter.sendMail({
from: 'YOUR-USERNAME',
to: 'RECEIVERS',
subject: 'Hello World',
text: 'Hello World'
});
console.log(JSON.stringify(result, null, 4));
}
Old Answer (before 2022-05-02)
I think that first you need to Allow less secure apps to access account setting in your Google account - by default this settings is off and you simply turn it on. Also you need to make sure that 2 factor authentication for the account is disabled. You can check how to disable it here.
Then I use the following script to send emails from a gmail account, also tested with yahoo and hotmail accounts.
const nodemailer = require('nodemailer');
let transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 587,
secure: false,
requireTLS: true,
auth: {
user: 'your.gmail.account#gmail.com',
pass: 'your.password'
}
});
let mailOptions = {
from: 'your.gmail.account#gmail.com',
to: 'receivers.email#domain.example',
subject: 'Test',
text: 'Hello World!'
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error.message);
}
console.log('success');
});
If you put the previous code in send-email.js for example, open terminal and write:
node send-email
You should see in the console - success, if the email was send successfully or the error message returned by nodemailer
Don't forget to first do the setting - Allow less secure apps to access account.
I hope this code will be useful for you. Good Luck!
If you have enabled 2-factor authentication on your Google account you can't use your regular password to access Gmail programmatically. You need to generate an app-specific password and use that in place of your actual password.
Steps:
Log in to your Google account
Go to My Account > Sign-in & Security > App Passwords
(Sign in again to confirm it's you)
Scroll down to Select App (in the Password & sign-in method box)
and choose Other (custom name)
Give this app password a name, e.g. "nodemailer"
Choose Generate
Copy the long generated password and paste it into your Node.js script instead of your actual Gmail password. (You don't need the spaces.)
Your script will now look like this:
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'YOUR-GMAIL-USERNAME#gmail.com',
pass: 'YOUR-GENERATED-APP-PASSWORD'
}
});
I hope this helps someone.
https://myaccount.google.com/lesssecureapps if it is OFF, turn it ON to enable lesssecureapps.
(i had same issue turn it on resolve my issue)
May 2022, google has remove this below the link of option ( https://myaccount.google.com/lesssecureapps if it is OFF, turn it ON to enable lesssecureapps. )
because it's risky to connect third party in google..
so, gmail has provide app password. where you can use into app(application)
> go to google > my account > security > 2-two steps verification(just verified your number by otp or call) >
> Scroll down to Select App (in the Password & sign-in method box) and choose Other (custom name)
> Give this app password a name, e.g. "nodemailer"
> Copy Generate password and paste it into your Node.js script instead of your actual Gmail password. (You don't need the spaces.)
once you copied app p/w, just regsiter for smtp on https://www.smtper.net/ (tick all option and don't left any field to fill up )
then click on submit (check gmail acc)
nodemailer code
const nodemailer = require('nodemailer');
const smtpTransport = require('nodemailer-smtp-transport');
var transporter = nodemailer.createTransport(smtpTransport({
service: 'gmail',
host: 'smtp.gmail.com',
port: 587,
secure: false,
auth: {
user: 'your.gmail.account#gmail.com',
pass: 'app password'
}
}));
let mailOptions = {
from: 'your.gmail.account#gmail.com',
to: 'receivers.email#domain.example',
subject: 'Test',
text: 'Hello World!'
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error.message);
}
console.log('success');
});
for more better understanding follow this 2links are given in below
offical smtp : https://nodemailer.com/smtp/
setup free google smtp server : https://www.youtube.com/watch?v=ql5Dex4m40w
Make sure you are using the right port: ie port: 587 as of now.
Visit this link to allow Less secure App access: https://myaccount.google.com/lesssecureapps
Enable the recaptcha at this link: https://accounts.google.com/b/0/DisplayUnlockCaptcha
Wait for a few minutes and try to send an email.
Alternatively use sendgrid. It has a free version.
If you are not seeing the emails in your inbox, check the Spam folder.
I encountered the same problem, i solved it as follows:
GOTO https://admin.google.com and Login with the main account you used for setting up the business account and create users. Remember to use the main Email ID.
Click on the Security Icon and you'll be taken to this page where you'll see Less secure apps section, click on it.
Now You'll see this, allow users or give permission here.
And you're not done yet, Not Go to the below link:
https://myaccount.google.com/u/1/lesssecureapps
Now you'll see the switch. Enable it and try it'll definitely work.
Peace :)
You have to allow Less-Secure-Apps to access account settings in your google account - by default, this setting is off and you can simply turn it on.
Image example
There are some account settings that are necessary for you to send through it using SMTP.
If you have two-step verification enabled on the account, you will need to use an application specific password (created in the Gmail account) in the device settings: Signing in using application-specific passwords
If not, please try this: sign into the Gmail account using a web browser at https://mail.google.com, then go to Settings > Accounts and Import > Other Google Account settings. Under Security, scroll down and enable access for less secure apps. This setting is required to enable SMTP, POP or IMAP access.
If there is still a problem, try clearing Captcha: visit https://accounts.google.com/DisplayUnlockCaptcha and sign in with the Gmail username and password. If necessary (it's usually not), enter the letters in the distorted picture then press Continue. This will allow ten minutes for the device to register as an approved connection. Note that you must use the account you are trying to add to the device - if the browser is already signed into another account, you must sign out first. Also, you must trigger the device to make a connection within ten minutes of pressing Continue.
Explanation from Google Support team
You are using gmail service so your mail must be in gmail:
var transport = nodemailer.createTransport({
service:'gmail',
auth: {
user: "asdfqweerrccb#gmail.com",
pass: "qwerr#wee"
}
});
var mailOptions = {
from: "transactions#gmail.com",
to:'umaraja1124#gmail.com',
subject: req.body.subject+"nodejs working ?",
text: "Hello world ?",
}
transport.sendMail(mailOptions, function(error, response){
if(error){
res.send("Email could not sent due to error: "+error);
console.log('Error');
}else{
res.send("Email has been sent successfully");
console.log('mail sent');
}
});

Node.js Nodemailer And SES - Error: No transport method defined

I am using nodemailer to send emails with SES. I am setting it up like this:
require("nodemailer").createTransport("SES", {
AWSAccessKeyID: "AKIAJZFUSYQJNEX3VS2A",
AWSSecretKey: "XXX", //real information removed
SeviceUrl:"https://email.us-west-1.amazonaws.com"
}),
When I Send The Email I Get:
Error: No transport method defined
Any ideas as to why this is happening?
*EDIT:*Tried Both solutions, and they did not work
You have to use your transport on sending mail. Just try as follows,
var nodemailer = require("nodemailer");
var transport = nodemailer.createTransport("SES", {
AWSAccessKeyID: "AKIAJZFUSYQJNEX3VS2A",
AWSSecretKey: "XXX",
SeviceUrl:"https://email.us-west-1.amazonaws.com"
}),
//On sending mail
nodemailer.sendMail({
transport : transport, //pass your transport
sender : 'senderid#email.com' ,
to : 'receiverid#email.com',
subject : "SUBJECT",
html: '<p> Hello World </p>'
})
Note: Here I assume, your transport is valid one and your key is enough permission(Network permission as well.)
Your ServiceUrl is configured incorrectly. Amazon SES is only available in us-east-1 at this time. Please set ServiceUrl to https://email.us-east-1.amazonaws.com.
Also, for future reference, please do not share your AWS Secret Key. I strongly recommend that you rotate your AWS keys since they were posted earlier in your question.

Resources