Configure SES to route traffic to a preauthorized Gmail account with Terraform.
MIT License
Configure SES to route traffic to a preauthorized Gmail account with Terraform.
For personal use:
Configure SES for receiving mail, and create the appropriate MX
records on your domain(s)
Create the module somewhere (and configure a Terraform state/handle other boilerplate)
Instantiate this module:
module "ses-to-gmail" {
source = "github.com/skeggse/terraform-aws-ses-to-gmail"
name = "terraform-email-pipe" # Prefix for all the resources we create.
deploy_bucket = "myorg-lambda-deploy-myregion" # The bucket hosting the Lambda's code.
s3_bucket_name = "The bucket that will host the incoming SES messages."
recipients = ["mydomain.com"] # Can be individual addresses or whole domains.
google_oauth = {
client_id = "EXAMPLE.apps.googleusercontent.com"
# Example parameters - you determine where these are stored.
secret_parameter = "/Dev/ServiceProviders/GoogleClient"
refresh_parameter = "/Dev/TenantCredentials/Google"
}
ses_rule_set_id = "default-rule-set" # Optional.
}
Create a new GCP project, and configure a new OAuth 2.0 Client ID pair.
Use the OAuth Playground to get a refresh token
for your personal Google account with the https://www.googleapis.com/auth/gmail.insert
and
https://www.googleapis.com/auth/gmail.modify
scopes. You'll can use the gear icon to provide
your own OAuth credentials, which simplifies this process.
Create two new parameters in SSM parameter store: one for the client secret and one for the refresh token.
client_id
and client_secret
. In the/Dev/ServiceProviders/GoogleClient
parameter with a value that{"client_id":"EXAMPLE.apps.googleusercontent.com","client_secret":"0cPppYgzfKdHyysI1sPpZF4N"}
.refresh_token
. In the example above,/Dev/TenantCredentials/Google
parameter with a value that looks like{"refresh_token":"Yy6VnmnpMWdj4zgyLqJ1PQ"}
.Plug the new client ID into the google_oauth
object in the module, along with the names of the
SSM parameters provisioned.
terraform apply
refresh_token
Instead of using the OAuth Playground to get a refresh token once, which may in rare cases cease
functioning, consider using terraform-aws-oauth2-authenticator
to simplify reauthorization
following the refresh token being revoked:
locals {
client_id = "EXAMPLE.apps.googleusercontent.com"
secret_parameter = "/Dev/ServiceProviders/GoogleClient"
}
module "ses-to-gmail" {
...
google_oauth = {
client_id = local.client_id
secret_parameter = local.secret_parameter
token_parameter = module.authorizer.service_token_parameters.google
}
}
module "authorizer" {
source = "github.com/skeggse/terraform-aws-oauth2-authenticator"
# Prefix for resource names.
name = "authorizer"
parameter_prefix = "/Dev/TenantCredentials"
services = {
google = {
client_id = local.client_id
secret_parameter = local.secret_parameter
extra_params = {
access_type = "offline"
}
scopes = [
"https://www.googleapis.com/auth/gmail.insert",
"https://www.googleapis.com/auth/gmail.modify",
]
authorization_endpoint = "https://accounts.google.com/o/oauth2/v2/auth"
token_endpoint = "https://oauth2.googleapis.com/token"
token_endpoint_auth_method = "parameter"
# The module also checks the email_verified field in the id_token.
identity_field = "email"
identify_with_openid = true
permitted_identities = ["[email protected]"]
}
}
}
The Lambda currently does not attempt to deduplicate emails it inserts into Gmail, which helps avoid granting the Lambda read permissions to your email. If we needed to deduplicate incoming emails, we'd either have to keep a record of emails we've received somewhere (money + complexity), or we'd need to search via Gmail's API for an existing copy of the email.
The Lambda does not attempt to handle threading in any sort of clean manner.
The Lambda also does not attempt to pass Gmail's SPF checks; Gmail sees the message as being sent from some random Amazon, even though it's being uploaded via the Gmail API.
Gmail-to-Gmail, it takes about 15 seconds from hitting send to the email appearing in the recipient's inbox. This may vary depending on whether the Lambda is warm, and the message size.