I am trying to send an email from an AWS lambda function. However, I get this error
INFO MessageRejected: Email address is not verified. The following identities failed the check in region US-EAST-1: testemail#gmail.com, support#mydomain.com
Both identities are verified in ap-southeast-2 and the lambda function is in the same region. If I am running the function from ap-southeast-2 and all my email configurations, including SMTP point to ap-southeast-2, why is the verification happening in us-east-1
Below is my code
const SES = new AWS.SES({ region: "us-east-1" });
const sendEmail = async (event) => {
const params = getNotificationParams(event);
console.log(params);
if (!params || params.error) {
return Responses._400({
message: params.error,
});
}
try {
await SES.sendTemplatedEmail(params).promise();
return Responses._200();
} catch (err) {
console.log(err);
return Responses._500({ message: "Error sending email" });
}
};
module.exports = {
handler: sendEmail,
};
The mistake was that I specified the wrong region (us-east-1) during SES initialization. Here is the fixed code with ap-southeast-2
const SES = new AWS.SES({ region: "ap-southeast-2" });
const sendEmail = async (event) => {
const params = getNotificationParams(event);
console.log(params);
if (!params || params.error) {
return Responses._400({
message: params.error,
});
}
try {
await SES.sendTemplatedEmail(params).promise();
return Responses._200();
} catch (err) {
console.log(err);
return Responses._500({ message: "Error sending email" });
}
};
module.exports = {
handler: sendEmail,
};
I created an AWS Lambda function to test new Cognito User Pool account creation but no account was created in user pool and no error shown in console log. I checked AWS Cloud Watch but no error was reported in cloud watch also.
START RequestId: ..... Version: $LATEST
END RequestId: .....
REPORT RequestId: ..... Duration: 80.12 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 84 MB
I changed my Lambda function to something simpler; describeUserPool. Still no error was thrown and no user pool info was printed in console. I added a console.log print within the describeUserPool callback function but that did not print.
The lambda function was created using AWS Console Lambda inline editor. Lambda function has AmazonESCognitoAccess policy attached (this policy has List/Read/Write access level to Cognito User Pools).
Can anyone shed some lights on what I've gotten wrong?
Thank you very much in advance.
var aws = require('aws-sdk');
aws.config.update({
accessKeyId: 'access_key_id',
secretAccessKey: 'secret_access_key',
region: 'us-east-1',
apiVersion: '2016-04-18'
});
var cognito = new aws.CognitoIdentityServiceProvider();
var params = {
UserPoolId: 'us-region-user-pool-id'
};
exports.handler = async (event) => {
cognito.describeUserPool(params, function(err, data) {
console.log('hello from inside function');
if (err) {
console.log(err);
} else {
console.log(data);
}
});
};
If I included an incorrect params in AdminCreateUser it reported error
var aws = require('aws-sdk');
aws.config.update({
accessKeyId: 'access_key_id',
secretAccessKey: 'secret_access_key',
region: 'us-east-1',
apiVersion: '2016-04-18'
});
var cognito = new aws.CognitoIdentityServiceProvider();
var params = {
UserPoolId: 'us-region-user-pool-id'
Username: 'someone',
TemporaryPassword: '11223344',
DesiredDeliveryMediums: 'EMAIL',
MessageAction: 'SUPPRESS',
UserAttributes: [
{
Name: 'Email',
Value: 'someone#example.com'
},
{
Name: 'Family_Name',
Value: 'One'
},
{
Name: 'Given_Name',
Value: 'Some'
},
{
Name: 'Phone_Number_verified',
Value: 'True'
},
{
Name: 'Email_verified',
Value: 'True'
}
],
};
exports.handler = async (event) => {
cognito.adminCreateUser(params, function(err, data) {
console.log('hello from inside function');
if (err) {
console.log(err);
} else {
console.log(data);
}
});
};
I received the following error message in Lambda inline editor console:
Response:
null
Request ID:
"6e50fdb4-e437-4b84-be7b-3caaeb5b0a98"
Function Logs:
ncCredentials (/var/runtime/node_modules/aws-sdk/lib/config.js:391:24)
at Config.getCredentials (/var/runtime/node_modules/aws-sdk/lib/config.js:411:9) {
code: 'MultipleValidationErrors',
errors: [
InvalidParameterType: Expected params.DesiredDeliveryMediums to be an Array
at ParamValidator.fail (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:50:37)
at ParamValidator.validateType (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:232:10)
at ParamValidator.validateList (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:99:14)
at ParamValidator.validateMember (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:90:21)
at ParamValidator.validateStructure (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:75:14)
at ParamValidator.validateMember (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:88:21)
at ParamValidator.validate (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:34:10)
at Request.VALIDATE_PARAMETERS (/var/runtime/node_modules/aws-sdk/lib/event_listeners.js:126:42)
at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
at callNextListener (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:96:12) {
code: 'InvalidParameterType',
time: 2020-05-31T21:59:35.116Z
},
InvalidParameterType: Expected params.UserAttributes[3].Value to be a string
at ParamValidator.fail (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:50:37)
at ParamValidator.validateType (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:232:10)
at ParamValidator.validateString (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:154:32)
at ParamValidator.validateScalar (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:130:21)
at ParamValidator.validateMember (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:94:21)
at ParamValidator.validateStructure (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:75:14)
at ParamValidator.validateMember (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:88:21)
at ParamValidator.validateList (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:103:14)
at ParamValidator.validateMember (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:90:21)
at ParamValidator.validateStructure (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:75:14) {
code: 'InvalidParameterType',
time: 2020-05-31T21:59:35.116Z
},
InvalidParameterType: Expected params.UserAttributes[4].Value to be a string
at ParamValidator.fail (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:50:37)
at ParamValidator.validateType (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:232:10)
at ParamValidator.validateString (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:154:32)
at ParamValidator.validateScalar (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:130:21)
at ParamValidator.validateMember (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:94:21)
at ParamValidator.validateStructure (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:75:14)
at ParamValidator.validateMember (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:88:21)
at ParamValidator.validateList (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:103:14)
at ParamValidator.validateMember (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:90:21)
at ParamValidator.validateStructure (/var/runtime/node_modules/aws-sdk/lib/param_validator.js:75:14) {
code: 'InvalidParameterType',
time: 2020-05-31T21:59:35.116Z
}
],
time: 2020-05-31T21:59:35.173Z
}
END RequestId: 6e50fdb4-e437-4b84-be7b-3caaeb5b0a98
REPORT RequestId: 6e50fdb4-e437-4b84-be7b-3caaeb5b0a98 Duration: 122.82 ms Billed Duration: 200 ms Memory Size: 128 MB Max Memory Used: 80 MB Init Duration: 356.12 ms
Found this post cognito admin not giving error. Suggestion by #thopaw solved the issue that I was having.
By changing it to promise() base it works as expected.
Thank you guys for your time.
In case anyone came across this, below is the updated code.
exports.handler = async (event, context) => {
console.log('starts');
var data;
try {
const data = await cognito.adminCreateUser(params).promise();
} catch (error) {
console.log(error);
}
};
Now day we can use the AWS StepFunctions if we want to make an lambda function to call another one.
But for now I need do support the code in production that was written before the StepFunctions time.
For that reason I need to understand how it works. I was trying to create a very simple lambda calling another lambda function trough AWS-SDk.
I have the follow serverless.yml
service: lambdaCallLambda
provider:
name: aws
runtime: nodejs6.10
functions:
hello:
handler: handler.hello
funcOne:
handler: handler.funcOne
funcTwo:
handler: handler.funcTwo
#Must install aws-sdk. #npm install --save aws-sdk
And this is the handler.js:
'use strict';
//https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html
var Lambda = require('aws-sdk/clients/lambda');
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'hello',
input: event,
}),
};
callback(null, response);
};
module.exports.funcOne = (event, context, callback) => {
var text='';
var i = 0;
for (i = 0; i < 5; i++) {
text += "The number is " + i + "\n";
}
console.log(text);
//https://docs.aws.amazon.com/general/latest/gr/rande.html
const lambda = new Lambda({
region: 'us-east-1'
});
console.log('control 3');
/*
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#constructor-property
To invoke a Lambda function
This operation invokes a Lambda function
https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html
Payload - JSON that you want to provide to your Lambda function as input.
*/
var params = {
ClientContext: "lambdaCallLambda",
FunctionName: "lambdaCallLambda-dev-funcOne",
InvocationType: "Event",
LogType: "Tail",
Payload: '{"jsonKey2":123}',
Qualifier: "1"
};
lambda.invoke(params, function(err, data) {
if (err){
console.log('control error\n');
console.log(err, err.stack); // an error occurred
}
else{
console.log('control OK\n');
console.log(data); // successful response
}
/*
data = {
FunctionError: "",
LogResult: "",
Payload: <Binary String>,
StatusCode: 123
}
*/
});
};
module.exports.funcTwo = async (event, context) => {
return 2;
//return '{"funcTwo":20000}';
//console.log("funcTwo = " + event);
};
After deploy sls deploy and call funcOne I get this 2 outputs:
LOCAL:
sls invoke local --function funcOne
Serverless: INVOKING INVOKE
The number is 0
The number is 1
The number is 2
The number is 3
The number is 4
control 3
control OK
{ StatusCode: 202, Payload: '' }
Invoking remotely in AWS:
sls invoke --function funcOne
{
"errorMessage": "Unexpected token (",
"errorType": "SyntaxError",
"stackTrace": [
" ^",
"SyntaxError: Unexpected token (",
"createScript (vm.js:56:10)",
"Object.runInThisContext (vm.js:97:10)",
"Module._compile (module.js:542:28)",
"Object.Module._extensions..js (module.js:579:10)",
"Module.load (module.js:487:32)",
"tryModuleLoad (module.js:446:12)",
"Function.Module._load (module.js:438:3)",
"Module.require (module.js:497:17)",
"require (internal/module.js:20:19)"
]
}
Error --------------------------------------------------
Invoked function failed
For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
Get Support --------------------------------------------
Docs: docs.serverless.com
Bugs: github.com/serverless/serverless/issues
Issues: forum.serverless.com
Your Environment Information -----------------------------
OS: linux
Node Version: 8.11.3
Serverless Version: 1.29.2
Does someone knows hat is happening here? Specially for the first scenario where I dont have any error.
This is what I get from the documentation
Parameters:
err (Error) — the error object returned from the request. Set to null if the request is successful.
data (Object) — the de-serialized data returned from the request. Set to null if a request error occurs. The data object has the following properties:
Status — (Integer)
It will be 202 upon success.
Update
After Eduardo Díaz suggestion -
I have changed lambda.invoke to:
lambda.invoke({
FunctionName: 'lambdaCallLambda-dev-funcOne',
Payload: JSON.stringify(event, null, 2)
}, function(error, data) {
if (error) {
console.log('control ErrorFoncOne\n');
context.done('error', error);
}
if(data.Payload){
console.log('control SuccessFoncOne\n');
context.succeed(data)
}
});
And this what I get for Local and Remote:
{
"errorMessage": "Unexpected token (",
"errorType": "SyntaxError",
"stackTrace": [
"Module.load (module.js:487:32)",
"tryModuleLoad (module.js:446:12)",
"Function.Module._load (module.js:438:3)",
"Module.require (module.js:497:17)",
"require (internal/module.js:20:19)"
]
}
It is a SyntaxError. There is a "(" somewhere.
I have found another developer with the same error here.
Note:
No error logs in CloudWatch
Try to send the event in the payload:
lambda.invoke({
FunctionName: 'name_lambda_function',
Payload: JSON.stringify(event, null, 2)
}, function(error, data) {
if (error) {
context.done('error', error);
}
if(data.Payload){
context.succeed(data.Payload)
}
});
I strongly suspect this problem is rooted in your handler signature for funcTwo:
module.exports.funcTwo = async (event, context) => {
NodeJS 6.10 does not support async/await. Node always complains about the token after the async token, for whatever reason. If you don't use a fat arrow function:
module.exports.funcTwo = async function(event, context) {
Node will complain: Unexpected token function.
Options
Deploy the function to NodeJS 8.10 instead.
Get rid of the async keyword in the handler signature.
Use a build tool (like serverless-webpack) to transpile the function down to ES6 (or lower).
Note: If you stick with the 6.10 runtime, I think you'll want to do something like context.succeed(2); or callback(null, 2);, rather than return 2;. Simply using a return statement does seem to work on 8.10.
I have found the issue. We need JSON.stringfy in the playload in lamdda.invoke method. No extra parameters are needed. Only the JSON as per the documentation.
lambda.invoke({
FunctionName: 'lambdaCallLambda-dev-funcTwo',
Payload: JSON.stringify({"jsonKey2":i})
...
From the AWS documentation for playload we have:
Payload
JSON that you want to provide to your Lambda function as input.
Note:
the async in front of the functions
lambda.invoke({
FunctionName: 'lambdaCallLambda-dev-funcTwo',
Payload: JSON.stringify({"jsonKey2":i})
}, async function(error, data) { ...
and
module.exports.funcTwo = async(event, context, callback) => { ...
Gives me this output:
Loop nb=1
Loop nb=2
Loop nb=3
Loop nb=4
Loop nb=5
{"message":"hello from funcTwo","event":{"jsonKey2":3}}
{"message":"hello from funcTwo","event":{"jsonKey2":2}}
{"message":"hello from funcTwo","event":{"jsonKey2":1}}
{"message":"hello from funcTwo","event":{"jsonKey2":5}}
{"message":"hello from funcTwo","event":{"jsonKey2":4}}
While the absence of async gives me:
Loop nb=1
Loop nb=2
Loop nb=3
Loop nb=4
Loop nb=5
{"message":"hello from funcTwo","event":{"jsonKey2":1}}
{"message":"hello from funcTwo","event":{"jsonKey2":2}}
{"message":"hello from funcTwo","event":{"jsonKey2":3}}
{"message":"hello from funcTwo","event":{"jsonKey2":4}}
{"message":"hello from funcTwo","event":{"jsonKey2":5}}
I'm going to share the handle.js code just in case someone else needs it:
'use strict';
//https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html
var Lambda = require('aws-sdk/clients/lambda');
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'hello',
input: event,
}),
};
callback(null, response);
};
/*
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#constructor-property
To invoke a Lambda function
This operation invokes a Lambda function
https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html
Payload - JSON that you want to provide to your Lambda function as input.
Serverless Framework: Lambdas Invoking Lambdas
https://lorenstewart.me/2017/10/02/serverless-framework-lambdas-invoking-lambdas/
How to escape async/await hell
https://medium.freecodecamp.org/avoiding-the-async-await-hell-c77a0fb71c4c
Iterating a Loop Using Lambda
https://docs.aws.amazon.com/step-functions/latest/dg/tutorial-create-iterate-pattern-section.html
AWS Lambda “Process exited before completing request”
https://stackoverflow.com/questions/31627950/aws-lambda-process-exited-before-completing-request
Class: AWS.Lambda
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#constructor-property
Invoke
https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#API_Invoke_RequestSyntax
Programming Model(Node.js)
https://docs.aws.amazon.com/lambda/latest/dg/programming-model.html
AWS Lambda Examples
https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/lambda-examples.html
*/
//The event is a file inserted in S3. This function funcOne reads the file and loop trough all quantities of products.
//Invoking a lamda function funcTwo for each process in the loop.
module.exports.funcOne = (event, context, callback) => {
//https://docs.aws.amazon.com/general/latest/gr/rande.html
const lambda = new Lambda({
region: 'us-east-1'
});
//Loop
//nbProducts = loop trough the products JSON list in S3
var nbProducts=5;
for (let i = 1; i <= nbProducts; i++) {
console.log('Loop nb='+i+'\n');
lambda.invoke({
FunctionName: 'lambdaCallLambda-dev-funcTwo',
Payload: JSON.stringify({"jsonKey2":i})
}, async function(error, data) {
if (error) {
//console.log('control ErrorFoncOne\n');
context.done('error', error);
}
if(data.Payload){
//console.log('control SuccessFoncOne\n');
console.log(data.Payload);
//context.succeed(data)
}
});
}
};
module.exports.funcTwo = async(event, context, callback) => {
callback(null, { message: 'hello from funcTwo', event });
};
just a change of one line would get you the respose
do change in params
'use strict';
//https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html
var Lambda = require('aws-sdk/clients/lambda');
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'hello',
input: event,
}),
};
callback(null, response);
};
module.exports.funcOne = (event, context, callback) => {
var text='';
var i = 0;
for (i = 0; i < 5; i++) {
text += "The number is " + i + "\n";
}
console.log(text);
//https://docs.aws.amazon.com/general/latest/gr/rande.html
const lambda = new Lambda({
region: 'us-east-1'
});
console.log('control 3');
var params = {
ClientContext: "lambdaCallLambda",
FunctionName: "lambdaCallLambda-dev-funcOne",
InvocationType: "RequestResponse", /* changed this line from
"Event" to "RequestResponse"*/
LogType: "Tail",
Payload: '{"jsonKey2":123}',
Qualifier: "1"
};
lambda.invoke(params, function(err, data) {
if (err){
console.log('control error\n');
console.log(err, err.stack); // an error occurred
}
else{
console.log('control OK\n');
console.log(data); // successful response
}
/*
data = {
FunctionError: "",
LogResult: "",
Payload: <Binary String>,
StatusCode: 123
}
*/
});
};
module.exports.funcTwo = async (event, context) => {
return 2;
//return '{"funcTwo":20000}';
//console.log("funcTwo = " + event);
};
I see the following error occasionally in my ec2 instance that uses DynamoDB heavily
{ message: 'Could not load credentials from any providers',
code: 'CredentialsError',
errno: 'ECONNREFUSED',
syscall: 'connect',
address: '169.254.169.254',
port: 80,
time: 2018-07-05T10:02:37.690Z,
originalError:
{ code: 'ECONNREFUSED',
errno: 'ECONNREFUSED',
syscall: 'connect',
address: '169.254.169.254',
port: 80,
message: 'connect ECONNREFUSED 169.254.169.254:80' } } }
The way I am using the AWS sdk to connect and get data from DynamoDB is like the following
'use strict'
const BluebirdPromise = require('bluebird')
AWS.config.setPromisesDependency(BluebirdPromise)
const DocumentClient = AWS.DynamoDB.DocumentClient
class DynamoOne {
get({
key
}) {
return new DocumentClient().get({ // creating new instance every time i want to get Item
Key: key,
TableName: 'TABLE_NAME',
ConsistentRead: consistent,
})
.promise()
.catch(e => console.trace(key, e))
}
}
new DynamoOne.get({
id: 1
}).then((item) => {
console.log(1, item)
})
Is this the correct way to use it ? or I should create new DocumentClient() once and use it all over , like the following code
'use strict'
const BluebirdPromise = require('bluebird')
AWS.config.setPromisesDependency(BluebirdPromise)
const DocumentClient = new AWS.DynamoDB.DocumentClient() // creating new instance once
class DynamoTwo {
get({
key
}) {
return DocumentClient.get({ // reuse DocumentClient
Key: key,
TableName: 'TABLE_NAME',
ConsistentRead: consistent,
})
.promise()
.catch(e => console.trace(key, e))
}
}
new DynamoTwo.get({
id: 1
}).then((item) => {
console.log(1, item)
})
Which one is the correct one DynamoOne or DynamoTwo ?
After researching and asking in github aws repo
I found that the correct way is to use DynamoTwo
I've been trying to get push notifications to work with my Parse application. I tried to do so my adding the below code into my Parse server.js file but my server does not start up again when this code is contained inside of the file. I have my p12 file available and linked in the code below (on my actual sever) as well so Im not sure what the issue is.
push: {
android: {
senderId: '...',
apiKey: '...'
},
ios: {
pfx: '/file/path/to/XXX.p12',
passphrase: '', // optional password to your p12/PFX
bundleId: '',
production: false
}
}
My server is running on an Amazon EC2 instance as well.
Are you using AWS SNS to use push notification? If so, you can try setting this in your server code:
function sendPhoneNotification() {
AWS = require('aws-sdk');
AWS.config.update({
accessKeyId: '***',
secretAccessKey: '***',
region: 'ap-southeast-1'
});
var sns = new AWS.SNS();
var promise = new Parse.Promise();
sns.createPlatformEndpoint({
PlatformApplicationArn: '***',
Token: "***"
}, function (err, data) {
if (err) {
console.log("Error in endpoint" + err.stack);
//res.error("error stack 1: " + err.stack);
promise.reject(err.stack);
return promise;
}
var endpointArn = data.EndpointArn;
var payload = {
GCM: {
data: {
title: "YOUR TITLE",
message: "HELLO PUSH NOTIFICATION"
}
}
/* APNS: {
aps: {
alert: 'Hello World',
sound: 'default',
badge: 1
}
}*/
};
// payload.APNS = JSON.stringify(payload.APNS);
payload.GCM = JSON.stringify(payload.GCM);
payload = JSON.stringify(payload);
var result = sns.publish({
Message: payload,
MessageStructure: 'json',
TargetArn: endpointArn
}, function (err, data) {
if (err) {
promise.reject(err.stack);
return promise;
}
res.success("push sent " + JSON.stringify(data));
});
});
return promise;
}