0

The lambda function is designed to use AWS Simple Email Service (SES) for email forwarding. The "sender" address stands for the AWS-hosted email inbox that is filling up with messages. These messages are forwarded to the final "recipient" address by calling the lambda function to execute an S3 action on each individual stored email file. Both sender and recipient email addresses are verified in the SES email verification system. However, SES is blocking email forwarding. It detects that the "sender" address equals the "original sender" address, which represents an unverified address by definition because it comes from a random website visitor. My question is, how do I change the final message structure to include the appropriate "From" field and make SES know that it is the verified owner of the inbox who is forwarding the message to the verified recipient address?

import email
import os
import boto3
from botocore.exceptions import ClientError

region = os.environ['Region']


def get_message_from_s3(message_id):
    incoming_email_bucket = os.environ['MailS3Bucket']
    incoming_email_prefix = os.environ['MailS3Prefix']
    print("incoming_email_bucket " + incoming_email_bucket)
    print("incoming_email_prefix " + incoming_email_prefix)

    if incoming_email_prefix:
        object_path = (incoming_email_prefix + "/" + message_id)
    else:
        object_path = message_id

    object_http_path = (
        f"http://s3.console.aws.amazon.com/s3/object/{incoming_email_bucket}/{object_path}?region={region}")
    print("object_http_path " + object_http_path)

    # Create a new S3 client.
    client_s3 = boto3.client("s3")

    # Get the email object from the S3 bucket.
    object_s3 = client_s3.get_object(Bucket=incoming_email_bucket, Key=object_path)
    # Read the content of the message.
    file = object_s3['Body'].read()

    file_dict = {
        "file": file,
        "path": object_http_path
    }

    return file_dict


def create_message(file_dict):
    sender = os.environ['MailSender']
    print("sender " + sender)

    recipient = os.environ['MailRecipient']
    print("recipient " + recipient)

    # The email message is loaded from a file.
    email_message_original = email.message_from_string(file_dict['file'].decode('utf-8'))

    # Create a new subject line.
    subject_original = email_message_original['Subject']
    print("subject_original " + subject_original)

    separator = ";"
    print("The message was received from "
          + separator.join(email_message_original.get_all('From'))
          + ". This message is archived at " + file_dict['path'])

    email_message_original.replace_header("From", sender)
    email_message_original.replace_header("To", recipient)

    message = {
        "Source": sender,
        "Destinations": recipient,
        # copy data from the original email message.
        "Data": email_message_original.as_string()
    }

    return message


def send_email(message):
    # Create a new SES client.
    client_ses = boto3.client('ses', region)

    # Send the email.
    try:
        # Provide the contents of the email.
        response = client_ses.send_raw_email(
            Source=message['Source'],
            Destinations=[
                message['Destinations']
            ],
            RawMessage={
                'Data': message['Data']
            }
        )

    # Display an error if something goes wrong.
    except ClientError as e:
        output = e.response['Error']['Message']
    else:
        output = "Email sent! Message ID: " + response['MessageId']

    return output


def lambda_handler(event, context):
    # get the email message id
    message_id = event['Records'][0]['ses']['mail']['messageId']
    print(f"Received message ID {message_id}")

    # Retrieve the file from the S3 bucket.
    file_dict = get_message_from_s3(message_id)

    # Create the message.
    message = create_message(file_dict)

    # Send the email and print the result.
    result = send_email(message)
    print(result)
GianniTee
  • 147
  • 1
  • 9
  • Have you tried sending a test email from the `sender` email in the SES region you configured in lambda? – jellycsc May 02 '20 at 18:03
  • I tested the program as much as I could. It is forwarding the incoming emails well from the original sender to the intermediary recipient address, and then to any verified final target address, but it only seems to work when the original sender address is verified. Much more testing is required still because I need to save the email that SES is refusing to send and then analyze it in detail. – GianniTee May 02 '20 at 19:08

1 Answers1

0

You'll find the From address under "Return-Path"

mailobject = email.message_from_string(file_dict['file'].decode('utf-8'))
sentFrom = mailobject['Return-Path']
Adam Winter
  • 1,680
  • 1
  • 12
  • 26