AWS Boto3 SES forwarding email with attachment - Special Character in 'From' header

Viewed 15

When forwarding an email through AWS SES using boto3, I am failing either to keep the attachment, or sending the email altogether if the 'From' header contains a special character.

I have tried this using SES resource's two functions, send_email and send_raw_email.

I can send emails just fine with the send_email function, except I could not find a way to keep any attachments.
I can send emails with attachments that have regular 'From' headers with send_raw_email, but if there is a special character in the 'From' header, I receive the below error:

When From is encoded with UTF-8:
An error occurred (InvalidParameterValue) when calling the SendRawEmail operation: Missing final '@domain'"
When From is encoded with ascii:
An error occurred (InvalidParameterValue) when calling the SendRawEmail operation: Local address contains control or whitespace

I have read through many SO posts, where examples with attachments always use the send_raw_email function. This makes sense to me as the send_email function only accepts a Body field from what I can tell, whereas send_raw_email accepts the email object in byte form. However, they seem to ignore the possibility of special characters in the 'From' header, or I am doing something wrong.

How can I avoid the above errors and preferably retain the original From header while also retaining any attachments?

Below is some simplified code that I use:

s3 = boto3.client("s3")
data = s3.get_object(Bucket=EMAIL_BUCKET, Key=f"{INCM_PREFIX_RAW}/{message_id}")
contents = data["Body"].read()
message = email.message_from_string(contents.decode("utf-8"))


characters = {"Ğ": "G", "Ü": "U", "Ş": "S", "İ": "I", "Ö": "O", "Ç": "C",
              "ğ": "g", "ü": "u", "ş": "s", "ı": "i", "ö": "o", "ç": "c", '"': "", " ": ""}
for character in characters: message_from = message_from.replace(character, characters[character])
if "<" in message_from:
    sender = message_from.split("<")[0]
    if "@" in sender: sender = "<example@example.com>"
    else: sender = sender + "<example@example.com>"
else: sender = "<example@example.com>"

message["From"] = sender

ses_client = boto3.client("ses")
response = ses_client.send_raw_email(
    Destinations=[destination],
    RawMessage={"Data": message.as_bytes()}
)

Here is the alternative approach of how I use the send_email function:

response = ses_client.send_email(
    Source=message["From"], Destination={"ToAddresses": [destination]},
    Message={"Subject": {"Data": message["Subject"]},
             "Body": {"Html": {"Data": message_html, "Charset": "utf-8"}}},
    ReplyToAddresses=[message_from], ReturnPath=message["From"]
)

Notes: I am using From as an address from my own domain, preceded by the original senders name, such as
'"John Doe" <my@domain.com>'

0 Answers
Related