Node.Js AWS SES - ETIMEDOUT when sending Email - node.js

I want to send a verification Email to new people signing up via AWS SES in Node.js:
var params = {
Destination: {
ToAddresses: [
'...',
]
},
Message: {
Body: {
Html: {
Data: '...',
Charset: 'utf-8'
},
Text: {
Data: '...',
Charset: 'utf-8'
}
},
Subject: {
Data: '...',
Charset: 'utf-8'
}
},
Source: '...',
ReturnPath: '...',
};
const ses = new AWS.SES({
my_accessKeyId,
my_secretAccessKey,
my_region,
})
ses.sendEmail(params, function (err, data) {
// ...
});
Unfortunately, nothing happens and after a minute or so I get the following error:
{ Error: connect ETIMEDOUT 35.157.44.176:443
at Object._errnoException (util.js:992:11)
at _exceptionWithHostPort (util.js:1014:20)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1186:14)
message: 'connect ETIMEDOUT 35.157.44.176:443',
code: 'NetworkingError',
errno: 'ETIMEDOUT',
syscall: 'connect',
address: '35.157.44.176',
port: 443,
region: 'eu-central-1',
hostname: 'email.eu-central-1.amazonaws.com',
retryable: true,
time: 2018-10-18T16:52:00.803Z }
I am not sure if the error results from a mistake in my code, as I am currently only using the sandbox environment. But I verified the sending and receiving email, which should work fine even in sandbox mode.
P.S. I am not quite sure how to properly test my application when being in sandbox mode, as I am not allowed to send to unverified emails. Is it possible to request production access without a proper application running?

You need to change region from eu-central-1 to region where endpoint exist (eg. eu-west-1) in order to send emails out
https://docs.aws.amazon.com/ses/latest/DeveloperGuide/regions.html

It's not obvious, so we'll need to do some troubleshooting.
First, lets see if you can connect from your local machine to the SES API using the AWS CLI. Make sure you have set up the aws credentials using aws configure and try:
aws ses list-identities
If this works, you should see a list of validated email addresses.
If not, you will see an error (permissions maybe), or a timeout suggests a network connectivity issue.
Note on credentials: Don't include your credentials in your code, either configure a .credentials file, which happens when you used the aws configure above, load it from a shared json file or use environment variables (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY).
Next, try to do the same in code:
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set the region
AWS.config.update({region: 'eu-central-1'});
// Create SES Client
const ses = new AWS.SES({apiVersion: '2010-12-01'})
// Create params
var params = {
IdentityType: "EmailAddress",
MaxItems: 123,
NextToken: ""
};
ses.listIdentities(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
After you set up your credentials as mentioned above, use this in your Send Email code to create the ses client:
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set the region
AWS.config.update({region: myregion});
// Create SES Client
const ses = new AWS.SES({apiVersion: '2010-12-01'})
Other things to check:
Make sure that all the email addresses are verified ("From", "Source", "Sender", or "Return-Path")
Make sure that you have the correct SES Access Keys
If using EC2, make sure that the security groups allow access to the AWS API.
I hope it's working by now, if not I can only say go to this page and make sure you haven't missed anything obvious.

You need to make sure your user your using to send the email
my_accessKeyId,
my_secretAccessKey,
has the correct IAM permissions (role attached to it) to send the email with ses. Test with the role SES full access I believe.

Related

Emails are not sent out after deploying to Lamba function

I'm using Nodemailer and SES to send out mails from my application, it works perfectly locally but doesn't work once I deploy to Lambda function, it returns with a "Endpoint request timed out" error message after it exceeds the 30 seconds API gateway time limit.
Note: The Lambda function has all the permissions required to send out SES mails.
I thought SES was the problem and I decided to use gmail instead, I got the same result. Checking my cloudwatch logs I find this error:
2022-11-16T06:54:23.547Z 6d967bf2-0837-4bd8-ae5f-011842656d15 INFO Error: Connection timeout
at SMTPConnection._formatError (/var/task/node_modules/nodemailer/lib/smtp-connection/index.js:790:19)
at SMTPConnection._onError (/var/task/node_modules/nodemailer/lib/smtp-connection/index.js:776:20)
at Timeout.<anonymous> (/var/task/node_modules/nodemailer/lib/smtp-connection/index.js:235:22)
at listOnTimeout (node:internal/timers:559:17)
at processTimers (node:internal/timers:502:7) {
code: 'ETIMEDOUT',
command: 'CONN'
}
Here's my function for sending out the mails, I have modified it so many times, I thought I was the one not structuring it properly.
const transporter = nodemailer.createTransport ({
service: 'gmail',
host: 'smtp.gmail.com',
port: 587,
secure: true,
auth: {
user: config.REACT_APP_EMAIL,
pass: config.REACT_APP_EMAIL_PASS,
},
});
const sendOutMail = async (receiver, emailSubject, body) => {
return transporter.sendMail({
from: config.REACT_APP_EMAIL,
to: receiver,
subject: emailSubject,
text: body,
html: '<div> ' + emailSubject + '</div>',
})
.then( results => {
console.log("Success:", results);
return true
})
.catch ( error => {
console.log("Error:", error);
return false
})
}
All modifications of my function works locally, but none works after I deploy
Since your lambda function runs inside a VPC, make sure you have internet access on this VPC. Otherwise you need to create a VPC Endpoint for SES so that your lambda can make that API call.
Here is the documentation for reference:
https://docs.aws.amazon.com/ses/latest/dg/send-email-set-up-vpc-endpoints.html

AWS.config.credentials returns null when using `serverless invoke local` command in NodeJS

I'm trying to run my AWS Lambda functions locally in a NodeJS environment with serverless invoke local [...] (as per https://www.serverless.com/framework/docs/providers/aws/cli-reference/invoke-local).
I keep getting error messages from appsync/graphql/apollo, stating: "Error: Network error: Response not successful: Received status code 403"
While debugging I found that I get the following:
appsync.js:
const AWS = require("aws-sdk");
console.log(AWS.config.credentials); // returns null
If I try to run the same file with node appsync.js then instead of null, AWS.config.credentials returns a valid credentials object (taken from my local .aws/credentials file.
So everything is where it should be, the only problem seems to be with the serverless invoke local ... function not allowing my aws-sdk package to access my .aws/credentials file.
How do I get aws-sdk to set AWS.config.credentials?
So the workaround that I managed to get working was to:
copy and paste my aws_access_key_id and aws_secret_access_key from .aws/credentials into my .env file.
Replace credentials: AWS.config.credentials, in my config object as follows:
const appSyncClientConfig = {
url: "https://xxxxxxxxx.appsync-api.eu-west-2.amazonaws.com/graphql", // from AppSync console.
region: "eu-west-2",
auth: {
type: AUTH_TYPE.AWS_IAM,
// credentials: AWS.config.credentials, REPLACED THIS WITH THE BELOW
credentials: {
accessKeyId: process.env.aws_access_key_id,
secretAccessKey: process.env.aws_secret_access_key,
},
},
offlineConfig: {
keyPrefix: "public",
},
disableOffline: true,
};
Now it's working.

AWS Credentials error: could not load credentials from any providers. ElasticSearch Service node.js

I was having a problem that I think should be posted on the internet. I may not know the internal issue, but I think I have a solution. Anyway the problem:
I'm hosting an ElasticSearch Service on AWS, and I'm trying to access that service locally and or through my ec2 service hosted on AWS.
But when I try to locally I get this error: Request Timeout after 30000ms
When I try it on my ec2 I get this error: AWS Credentials error: Could not load credentials from any providers
Here was how I set up the credentials and made the query:
const AWS = require('aws-sdk');
const connectionClass = require('http-aws-es');
const elasticsearch = require('elasticsearch');
try {
var elasticClient = new elasticsearch.Client({
host: "https://some-elastic.us-east-1.es.amazonaws.com/",
log: 'error',
connectionClass: connectionClass,
amazonES: {
region: 'us-east-1',
credentials: new AWS.Credentials('id', 'key')
}
});
elasticClient.indices.delete({
index: 'foo',
}).then(function (resp) {
console.log("Successful query!");
console.log(JSON.stringify(resp, null, 4));
}, function (err) {
console.trace(err.message);
});
} catch (err) {
console.log(err);
} finally {
}
So as stated I kept getting this error. I tried many other variations to pass the credentials.
My vague understanding of the problem is that the credentials being set in the amazonES object are being ignored, or that the region isn't being passed along with the credentials. So AWS doesn't know where to search for the credentials.
Anyway here is the solution:
AWS.config.update({
secretAccessKey: 'key',
accessKeyId: 'id',
region: 'your region ex. us-east-1'
});
var elasticClient = new elasticsearch.Client({
host: "https://some-elastic.us-east-1.es.amazonaws.com/",
log: 'error',
connectionClass: connectionClass,
amazonES: {
credentials: new AWS.EnvironmentCredentials('AWS'),
}
});
It's a bit of a buggy situation. I couldn't find this solution anywhere online and I hope it helps someone out who runs into the same errors in the future.

AWS SQS "ECONNREFUSED" when sending message

Trying to send Message to AWS SQS from nodejs. I keep getting this specific error
{ Error: connect ECONNREFUSED 127.0.0.1:443
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1161:14)
message: 'connect ECONNREFUSED 127.0.0.1:443',
errno: 'ECONNREFUSED',
code: 'NetworkingError',
syscall: 'connect',
address: '127.0.0.1',
port: 443,
region: 'us-east-1',
hostname: '',
retryable: true,
time: 2018-07-16T11:26:04.672Z }
I have set my credentials in my App, Given full access to my user for AWSSQSService. I can get all the details about the queue itself, queue names, etc. I just cannot send a message to the queue. My code below to send it
{
let AWS = require('aws-sdk');
AWS.config.update({region: constants.AWS.AWS_REGION});
let sqs = new AWS.SQS({apiVersion: '2012-11-05'});
let SQSQueueUrl = ' https://sqs.us-east-1.amazonaws.com/*queueName*';
let params = {
MessageBody: 'demo', /* required */
QueueUrl: SQSQueueUrl, /* required */
};
sqs.sendMessage(params, function(err, data) {
if(err)
console.log(err);
else
console.log(data);
});
}
So, I came across the same error, remove the space at the start of your SQSQueueUrl, it solves the error.
so go with
let SQSQueueUrl = 'https://sqs.us-east-1.amazonaws.com/queueName';
That comes up when you don't configure access key and secret; you can specify it either on line 2 with the config or via environment

Password reset with Parse on Azure & Postmark

I have migrated data from the parse website to Azure's version of parse and notice some components were missing like an email adapter. So I follow the instructions from here https://www.npmjs.com/package/parse-server-postmark-adapter. I'm able to receive email to change my password.
But I get this error when I click on the link to change my password,
"level":"error","message":"Uncaught internal server error. [Error: Can't set headers after they are sent.]
Can anyone explain why I'm getting this message? Also, I put the code to configure postmark in my config.js file.
Edit:
var PostmarkAdapter = require('parse-server-postmark-adapter');
module.exports = {
server: {
appName: 'myapp',
publicServerURL: 'http://myapp.azurewebsites.net/parse',
verifyUserEmails: true, // Enable email verification
emailAdapter: PostmarkAdapter({
apiKey: 'api-key-0000',
fromAddress: 'someemail#email.com',
})
},
dashboard: {},
storage: {},
push: {}
}

Resources