AWS EC2 SES SMTP PHPMailer¶
https://docs.aws.amazon.com/ses/latest/dg/setting-up.html
An AWS EC2 instance will be launched. Apache and PHP will be installed. SES will then be configured so that email can be sent from a PHP script. The script will use PHPMailer, installed using Composer.
An EC2 instance running Ubuntu 22.04 was launched from the AWS console. I followed the CodeNotes Ubuntu Server Configuration to install Apache and PHP. However after I ran sudo chown -R ubuntu:ubuntu /var/www
(which changes /var/www/ and /var/www/html directory ownerships to ubuntu from root), I then used the html directory as the root directory for my application to test SES.
I replaced the default index.html file in /var/www/html with an index.php file and now I can browse to http://<ipV4-address> and see the index.php file displayed as a web page.
Note that with SES you can only send email from addresses or domains that you prove to Amazon you own.
Overview¶
In order to be able to use PHPMailer (or other email software) to send emails we will need the following:
Ubuntu Server running PHP and Apache
Composer Package manager
PHPMailer
A verified domain, subdomain or email address as ‘From’ address
An smtp_username and password for your Amazon SES account
An SES SMTP endpoint host for an appropriate AWS region
The following sections help explain how to obtain these requirements.
SES SMTP Credentials¶
https://docs.aws.amazon.com/ses/latest/dg/send-email-concepts-credentials.html
These consist of a username and password. In my case the username was a 20 char alphanumeric (letters all uppercase) string and the password was a 47 char alphanumeric (letters upper and lower case) string. The same credentials can be used for any verified domain.
You need SMTP credentials for sending an email using the Amazon SMTP interface. SES SMTP credentials are a type of IAM credential. The credentials used are unique to each AWS Region. An IAM user can create SES SMTP credentials if the IAM user’s policy gives them permissions to access the following actions:
iam:ListUsers
iam:CreateUser
iam:CreateAccessKey
iam:PutUserPolicy
Create SES SMTP Credentials¶
https://docs.aws.amazon.com/ses/latest/dg/smtp-credentials.html
From Amazon Console go to Simple Email Service and click on SMTP Settings
Click on ‘Create SMTP credentials’
Enter or accept name of new IAM user and click Create
Show the Credentials and save them eg. in a password manager
Sender Identity¶
https://docs.aws.amazon.com/ses/latest/dg/creating-identities.html#verify-domain-procedure
(I think that) SES only allows emails to be sent from a verified sender identity which corresponds either to a verified domain subdomain or email address. For domains verification is through updates in the DNS records. For email, verification is through clicking a link in a verification email. You can verify both a domain and an email address in that domain. This will allow a greater range of capabilities than just one form of verification. To verify the identity of a domain:
go to SES
Ensure correct region is chosen at top of page
Click Verified identities
Click Create identity
Select Domain
Type in domain name
Assign a default configuration set ??? I did not tick the box.
Use a custom MAIL FROM domain. The MAIL FROM address must align with the From address which is necessary for DMARC. Can this be achieved from within the app? It can be done later. I did not tick the box.
DKIM-based domain verification. If the domain is registered with Route 53, SES will automatically update the DNS server (unless otherwise desired).
Tags can be added for organization of resources.
Click Create identity
CNAME records get added to the domain’s Route 53 DNS record
If domain is not hosted by Route 53 you have to update the domain’s DNS records where they are hosted.
I went through this procedure with the wrong region selected at the top of the page. So, I deleted the Domain identity and redid it correctly. I do not think the CNAME records added in the first attempt were removed. I removed the old records from the DNS record. They could be identified as they were the CNAME records not in the SES -> Verified identity -> DKIM section for the domain.
Send Test Email¶
Go to SES -> Verified identities
Click on an identity name
Click ‘Send test email’
Type in the part of the address before @ for the From-address
You can choose various test scenarios or send it to an Amazon verified email address.
Put in a Subject and (optional) body
Choose configuration set (optional)
Send test email
On the domain identity detail page, a message appeared - Successfully sent a test email to success@simulator.amazonses.com
Get Out of the Sandbox¶
https://docs.aws.amazon.com/ses/latest/dg/request-production-access.html
New accounts are placed in the SES sandbox:
Mail can only be sent to verified email addresses and domains or the SES mailbox simulator.
only! 200 messages can be sent per 24 hours
You can send a max of 1 email per second
When out of the sandbox you can send to any email but you have to verify the identities of ‘From’, ‘Sourse’, ‘Sender’ or ‘Return-Path’ addresses.
Request account removal from sandbox:
Does this apply to all verified identities (domains and email addresses)?
SES -> Account dashboard
Choose Request production access
Fill up the form and submit
It may take up to 24 hours…
SES SMTP Endpoints¶
https://docs.aws.amazon.com/ses/latest/dg/smtp-connect.html
To send email using the SES SMTP interface you connect to an SMTP endpoint. See: https://docs.aws.amazon.com/general/latest/gr/ses.html
For Europe, London (Region: eu-west-2) the SMTP endpoint is email-smtp.eu-west-2.amazonaws.com and the associated protocol is SMTP. The value of the SMTP endpoint is used in the PHPMailer script which sends email(s).
Connections should be encrypted using STARTTLS (ports 25, 587 or 2587) or TLS Wrapper (ports 465 and 2465). The choice may depend on the software you use eg PHPMailer
STARTTLS¶
SMTP client connects to SES SMTP endpoint on port 25, 287 or 2587
SMTP client issues EHLO command
Server announces it supports STARTTLS SMTP extension
SMTP client issues STARTTLS command, initiating TLS negotiation
SMTP client issues EHLO command over encrypted connection
SMTP session proceeds
Remove Throttle on Port 25¶
This is unnecessary as you can use port 587.
This seems to be specific to a single EC2 instance. So it is probably not worth doing for
https://aws.amazon.com/premiumsupport/knowledge-center/ec2-port-25-throttle/
Route 53 (or DNS record if hosted elsewhere)
Choose Hosted zones
Select a zone
Create Record
Choose Simple routing -> Next
Click ‘Define simple record’
Record Name, IP address of EC2 instance
Click ‘Define simple Record’
Click ‘Create Records’
Request to remove the port 25 restriction on your instance
Choose Support Centre
Click Create Case
Select Service limit increase
Limit Type: EC2 email
Open the link for EC2 email
Type in your email address (for correspondence I think) and Use case.
Optionally, fill in Elastic IP address and Reverse DNS record. This can help reduce the liklihood of emails being delivered to Spam. Hopefully the information can be supplied at a later date.
Submit
You should get an email telling you the port 25 restriction has been removed.
Create A record pointing to IP address of EC2 instance that will be hosting the SMTP service.
Using SES SMTP to send email¶
https://docs.aws.amazon.com/ses/latest/dg/send-email-smtp.html
Send Emails with PHP via SES SMTP¶
https://docs.aws.amazon.com/ses/latest/dg/send-using-smtp-programmatically.html
First install composer into the root of your project eg /var/www/example.com/public_html/ (instructions at https://getcomposer.org/download/). Then to install PHPMailer run php composer.phar require phpmailer/phpmailer
. Note that this should be done on the server not your local maching unless you are using that as a server for development purposes.
Now you should be able to send emails progromatically using a script.
PHP Script to Send Email¶
<?php
// Import PHPMailer classes into the global namespace
// These must be at the top of your script, not inside a function
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
// If necessary, modify the path in the require statement below to refer to the
// location of your Composer autoload.php file.
require 'vendor/autoload.php';
// Replace sender@example.com with your "From" address.
// This address must be verified with Amazon SES.
$sender = 'stevegreig@bgrgolf.com';
$senderName = 'Steve Greig';
// Replace recipient@example.com with a "To" address. If your account
// is still in the sandbox, this address must be verified.
$recipient = 'greigsteve@gmail.com';
// Replace smtp_username with your Amazon SES SMTP user name.
$usernameSmtp = '<SES SMTP user name>';
// Replace smtp_password with your Amazon SES SMTP password.
$passwordSmtp = '<SES SMTP password>';
// Specify a configuration set. If you do not want to use a configuration
// set, comment or remove the next line.
// $configurationSet = 'ConfigSet';
// If you're using Amazon SES in a region other than US West (Oregon),
// replace email-smtp.us-west-2.amazonaws.com with the Amazon SES SMTP
// endpoint in the appropriate region.
// $host = 'email-smtp.us-west-2.amazonaws.com';
$host = 'email-smtp.eu-west-2.amazonaws.com';
$port = 587;
// The subject line of the email
$subject = 'Amazon SES test (SMTP interface accessed using PHP)';
// The plain-text body of the email
$bodyText = "Email Test\r\nThis email was sent through the
Amazon SES SMTP interface using the PHPMailer class";
// The HTML-formatted body of the email
$bodyHtml = '<h1>Email Test</h1>
<p>This email was sent through the
<a href="https://aws.amazon.com/ses">Amazon SES</a> SMTP
interface using the <a href="https://github.com/PHPMailer/PHPMailer">
PHPMailer</a> class</p>';
$mail = new PHPMailer(true);
try {
// Specify the SMTP settings.
$mail->isSMTP();
$mail->setFrom($sender, $senderName);
$mail->Username = $usernameSmtp;
$mail->Password = $passwordSmtp;
$mail->Host = $host;
$mail->Port = $port;
$mail->SMTPAuth = true;
$mail->SMTPSecure = 'tls';
// $mail->addCustomHeader('X-SES-CONFIGURATION-SET', $configurationSet);
// Specify the message recipients.
$mail->addAddress($recipient);
// You can also add CC, BCC, and additional To recipients here.
// Specify the content of the message.
$mail->isHTML(true);
$mail->Subject = $subject;
$mail->Body = $bodyHtml;
$mail->AltBody = $bodyText;
$mail->Send();
echo "Email sent!" , PHP_EOL;
} catch (phpmailerException $e) {
echo "An error occurred. {$e->errorMessage()}", PHP_EOL; //Catch errors from PHPMailer.
} catch (Exception $e) {
echo "Email not sent. {$mail->ErrorInfo}", PHP_EOL; //Catch errors from Amazon SES.
}
Problems¶
https://docs.aws.amazon.com/ses/latest/dg/troubleshoot-smtp.html