Email not being sent / No errors AWS/SES - amazon-web-services

I have an AWS Lambda function:
sendEmail.js
const AWS = require('aws-sdk');
const ses = new AWS.SES();
function sendEmail(subject, message, senderEmail) {
const params = {
Destination: {
ToAddresses: [
process.env.VERIFIED_EMAIL
]
},
Message: {
Body: {
Text: {
Data: message,
Charset: 'UTF-8'
}
},
Subject: {
Data: subject,
Charset: 'UTF-8'
}
},
Source: process.env.VERIFIED_EMAIL,
ReplyToAddresses: [senderEmail]
}
return ses.sendEmail(params).promise();
}
module.exports = sendEmail;
Called from
index.js
const sendEmail = require('./sendEmail');
exports.handler = async (event, context) => {
return sendEmail(event.subject, event.message, event.email).then((response) => { context.done(null, 'Email sent')});
};
I have the env. variable VERIFIED_EMAIL set to a personal e-mail that is verified by AWS/SES.
My test case:
{
"email": "redacted#outlook.com",
"subject": "desc",
"message": "Hello!"
}
Which passes and returns "Email sent" but I don't actually receive an e-mail. I've also deployed the API-GATEWAY and I can call the API w/ Postman and I receive the same "Email sent" message but no e-mail is actually sent.
I don't think it should be an issue with being in sandbox mode because the email I am sending it from is verified.
PS:
When Looking at the SES management console it says that the emails are being sent (they take up part of the 200 daily quota) and then that none of them were bounced or rejected but simply deliveries.

A few things you should check with your SES before diving deeper.
In sandbox mode both "source email address" and "destination email address" have to be verified. Instead a mail won't be delivered.
In case you verify Email Domain so appropriate dns and DKIM records have to be added in your domain. Plus additional whitelist clearance is assumed if you use corporate domains.
Your IAM AWS user should be permitted to execute SES api calls. Check your policies and roles. Check Secret Key and Secret Id you use.
There might be problems when you use inappropriate email types and email sending endpoints (eg you try to send "SingleTemplatedMessage" via "BulkTemplatedMessage" endpoint)
Check all this things first.
Then you might try something else. In my project we use AWS SDK based on java to interact between BE and SES. It provides logs containing message statuses (if a message was sent successfully, rejected, its id and other errors if they occurred)
Additionally to keep track on every single message you send you can set up SES-SNS to exchange with notifications. It's described in the following article
https://sysgears.com/articles/how-to-track-email-status-with-amazon-ses-and-amazon-sns/
Other problems might occur in your mail client (spam filters etc)

Follow the check list to troubleshoot SES email sending:
Check the SMTP credential is ok or not using code shared by AWS
Same credential using in multiple application/IP may not work
Use minimum mail configuration, if you do not know setting value remove it, do not leave it with NULL.
Set, $config['charset'] = 'UTF-8'; // // 'UTF-8', 'ISO-8859-15'
Set, $config['newline'] = "\r\n"; // "\r\n" or "\n" or "\r"
Additional Check
Make sure trying to send email to the same domain if SES account is Sandbox
Check all outbound with mail TCP port is open
If using NATgateway Check both inbound and outbound with mail TCP port is open in open for the mail sending instance in it.

Related

How to send emails from django shell with AWS ses?

I have verified my domain with AWS SES and as a result my site successfully does send password verification emails (via allauth).
I would, however, also like to be able to send emails based on local scripts. To do this I have been using django shell_plus:
from django.core.mail import send_mail
send_mail("It works!", "This will get sent through anymail",
"me#mysite.com", ["me#mysite.com"])
I get output of '1' suggesting this the email has been sent successfully but I do not receive an email
I think my config is correct given that the site does successfully send emails:
EMAIL_BACKEND = "anymail.backends.amazon_ses.EmailBackend"
ANYMAIL = {
"AMAZON_SES_CLIENT_PARAMS": {
"aws_access_key_id": AWS_ACCESS_KEY_ID,
"aws_secret_access_key": AWS_SECRET_ACCESS_KEY,
"region_name": "us-east-1",
},
}
Can anyone explain what I need to do to send emails from the terminal i.e. without being directly logged into an AWS server?
Was a basic error - I had the required settings in my production config file, but not in my dev config file

Customizing OTP Authentication flow with AWS Amplify

I've currently integrated an OTP authentication signin flow to a React Native app with Amplify. The flow is as follows.
(I followed the guide provided in this article)
But right now I'm in the need of providing the option of sending the OTP code to a user entered email address in case if it is not received to the mobile number.
Initial thought was to trigger the create auth challenge lambda function via Amplify Auth.signUp by sending email attribute.
import Auth from '#aws-amplify/auth';
const sendVerificationToEmail = async (phone: number, email: string, password: string) => {
await Auth.signUp({
username: phone,
password,
attributes: {
email
} });
}
Then the lambda function can be remodified as follows to either send an email or SMS,
...
const email = event.request.userAttributes.email;
if (email) {
// Logic to send OTP verification code via SES
} else {
// Logic to send OTP via SNS
}
but this is not possible since we already have a user created in the cognito user pool. This attribute will not be passed to the lambda function.
What is the correct approach of achieving this ?
Easiest approach is, Setup lambda function for custom flow.
Create custom method to generate an OTP and save it to into a table and
then use SES to send OTP to email .
Create custom method to verify OTP.
Check OTP from table and verify it.
if(SUCCESS)
use admin to mark as verified
https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminConfirmSignUp.html

Configure a Custom SMS Message for MFA in AWS Cognito

I Am using AWS Cognito for authentication in a web application.
If a user Forgets their password I have a Lambda Function Trigger that sends a custom email with a link that has the users email address and the verification code in so they can click the link and just enter their new password.
So There is a new requirement that should allow the user to receive an sms, but currently it looks like if you enable MFA for sending the SMS, you can only customise the message in the console area and in the Lambda function,
this event.response.smsMessage does not seem to do anything.
So if the user has phone_number_verified true, it sends the sms without triggering the Lambda function.
exports.handler = function(event, context) {
if(event.triggerSource === "CustomMessage_ForgotPassword") {
var url = 'http://myurl.com/forgotpassword/'+ event.request.userAttributes.email+'/'+event.request.codeParameter
event.response.smsMessage = 'Password Reset: Click the link ' + url + ' or enter Verification Code: ' + event.request.codeParameter
event.response.emailSubject = " Password reset";
event.response.emailMessage = "Custom HTML goes here";
}
context.done(null, event);
};
This is currently the Lambda function configure on custom message trigger in the cognito User pool.
After a long discussion with AWS support, They came to the resolution that my SMS text was more than 140 chars. Yes 140, And then the SMS would not be sent rather the email would. No errors in logs or anything whatsoever.
So they said they will look into adding something in the logs that at least tells you that the SMS was not sent because the character limit was exceeded.

What is "cognitoUser.getAttributeVerificationCode"?

I'm convinced that Amazon goes out of its way to make understanding their platform as difficult as is possible.
I've read over the documentation regarding "cognitoUser.getAttributeVerificationCode" at Amazon only to have it make me even more confused!
Verify an Attribute
The following example verifies user attributes for an authenticated user.
cognitoUser.getAttributeVerificationCode('email', {
onSuccess: function (result) {
console.log('call result: ' + result);
},
onFailure: function(err) {
alert(err);
},
inputVerificationCode: function() {
var verificationCode = prompt('Please input verification code: ' ,'');
cognitoUser.verifyAttribute('email', verificationCode, this);
}
});
Can anyone help me understand what this is (cognitoUser.getAttributeVerificationCode) and/or how I would use it? I don't understand why I would verify an email attribute w/a verification code.
The verification code is sent to the users email. The user has to properly receive that email to retrieve the code and enter it in a UI so that the email is set to verified in Cognito. That user can then reset their password using that email.
What if the user had entered an incorrect email? Or their email system didn't allow them to receive the code sent by AWS?
By sending out a verification code, and having the user send it back, Cognito verifies that the email was entered correctly and belongs to that user. This can seem like a pain but is standard on many web platforms now days...The same process is needed with phone numbers for users in your Cognito user pool.

AWS Cognito Test Environment

I'm currently working on using AWS Cognito to manage user authentication for our application. One snag I'm running into is figuring out a good way to implement a "test" or "qa" environment.
I have a lot of automated tests for my APIs that will create users with random data. Obviously I don't want to Cognito to send out actual SMS or Email messages in this environment. Also when doing manual testing we will be creating users a lot with fake phone numbers and emails. Is there any way to turn the User Pool in "development" mode where all messages simply get logged some way?
You can write a pre sign up lambda function and auto confirm the user in the lambda function by setting the autoConfirmUser flag. In that case, Cognito doesn't send any SMSes or emails with confirmation codes. Example lambda below from the documentation (http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#aws-lambda-triggers-pre-registration-example).
exports.handler = function(event, context) {
// This Lambda function returns a flag to indicate if a user should be auto-confirmed.
// Perform any necessary validations.
// Impose a condition that the minimum length of the username of 5 is imposed on all user pools.
if (event.userName.length < 5) {
var error = new Error('failed!');
context.done(error, event);
}
// Access your resource which contains the list of emails of users who were invited to sign up
// Compare the list of email IDs from the request to the approved list
if(event.userPoolId === "yourSpecialUserPool") {
if (event.request.userAttributes.email in listOfEmailsInvited) {
event.response.autoConfirmUser = true;
}
}
// Return result to Cognito
context.done(null, event);
};
Here is what I did to create a "staging" environment User Pool in AWS Cognito that does not send real notifications to users. There were actually a couple different pieces involved, but I think I was able to get everything covered. That being said, it would sure be nice if Cognito simply provided a User Pool setting to turn off all notifications, that way I don't have to write environment specific logic into my code.
Prevent User Invitations
In our app we use the AdminCreateUser function to create users who get invited by other users. This function will normally send an invitation message to the new user's phone number or email. In order to prevent those invitations, you can provide MessageAction: 'SUPPRESS' as a parameter to the function arguments. Like so:
let params = {
UserPoolId: config.cognitoUserPoolId,
Username: uuid.v4(),
MessageAction: 'SUPPRESS', /* IMPORTANT! */
TemporaryPassword: user.phone_number.slice(-6),
UserAttributes: [
{ Name: 'given_name', Value: user.first_name },
{ Name: 'family_name', Value: user.last_name },
{ Name: 'phone_number', Value: user.phone_number }
]
};
cognito.adminCreateUser(params).promise().then(data => {
console.log(data);
});
Official docs for that here: http://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminCreateUser.html
Prevent User Attribute Update Verfications
In our production app, we want users to have to re-verify their phone number or email if it changes. But in our staging environment we don't actually need this. So uncheck the boxes for email and phone under the "Do you want to require verification of emails or phone numbers?" section in your User Pool settings.