Search code examples
amazon-web-servicespowershellamazon-sesaws-powershell

How to send SES RawEmail with Attachment through PowerShell


I'm trying to design a PowerShell script that utilizes AWS SES to send a RawEmail with a .csv attachment, but information is scant on how to actually attach the attachment:

PS C:\Users\jsmith_prod\Desktop\SSMSScript> ls

    Directory: C:\Users\jsmith_prod\Desktop\SSMS Script

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        2/16/2023   2:00 PM        1096846 Inventory.csv

PS C:\Users\jsmith_prod\Desktop\SSMSScript> Send-SES2Email -FromEmailAddress [email protected] -Destination_ToAddress [email protected] -Raw_Data .\Inventory.csv
0100018661480af8-6a5939bd-5f9a-4f2f-9aa8-084cd872b9a8-000000
PS C:\Users\jsmith_prod\Desktop\SSMSScript> 

When I try the above simple command, I only end up with an empty email, rather than an email with the attached .csv. According to AWS's documentation, attachments should be included under Raw_Data in order to highlight that this is a raw email. However, without any helpful error message, I can't figure out what's going wrong.


Solution

  • According to the Send-SES2Email documentation, the -Raw_Data argument is the raw email message itself, not an attachment. As you mentioned, attachments should be included under Raw_Data. The client must ensure that the message format complies with Internet email standards regarding email header fields, MIME types, and MIME encoding. The documentation defines criteria for raw messages and refers to RFC 5321 in that regard.

    Please note, that the message body must contain a properly formatted, raw email message, with appropriate header fields and message body encoding. Although it's possible to construct the raw message manually within an application, it's much easier to do so using existing mail libraries. Check out this documentation for examples of how properly construct raw email message with an attachment. With Python it can look something like this (take note of how an attachment is handled):

    import os
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    from email.mime.application import MIMEApplication
    
    # Replace [email protected] with your "From" address.
    # This address must be verified with Amazon SES.
    SENDER = "Sender Name <[email protected]>"
    
    # Replace [email protected] with a "To" address. If your account 
    # is still in the sandbox, this address must be verified.
    RECIPIENT = "[email protected]"
    
    # Specify a configuration set. If you do not want to use a configuration
    # set, comment the following variable, and the 
    # ConfigurationSetName=CONFIGURATION_SET argument below.
    CONFIGURATION_SET = "ConfigSet"
    
    # If necessary, replace us-west-2 with the AWS Region you're using for Amazon SES.
    AWS_REGION = "us-west-2"
    
    # The subject line for the email.
    SUBJECT = "Customer service contact info"
    
    # The full path to the file that will be attached to the email.
    ATTACHMENT = "path/to/customers-to-contact.xlsx"
    
    # The email body for recipients with non-HTML email clients.
    BODY_TEXT = "Hello,\r\nPlease see the attached file for a list of customers to contact."
    
    # The HTML body of the email.
    BODY_HTML = """\
    <html>
    <head></head>
    <body>
    <h1>Hello!</h1>
    <p>Please see the attached file for a list of customers to contact.</p>
    </body>
    </html>
    """
    
    # The character encoding for the email.
    CHARSET = "utf-8"
    
    # Create a multipart/mixed parent container.
    msg = MIMEMultipart('mixed')
    # Add subject, from and to lines.
    msg['Subject'] = SUBJECT 
    msg['From'] = SENDER 
    msg['To'] = RECIPIENT
    
    # Create a multipart/alternative child container.
    msg_body = MIMEMultipart('alternative')
    
    # Encode the text and HTML content and set the character encoding. This step is
    # necessary if you're sending a message with characters outside the ASCII range.
    textpart = MIMEText(BODY_TEXT.encode(CHARSET), 'plain', CHARSET)
    htmlpart = MIMEText(BODY_HTML.encode(CHARSET), 'html', CHARSET)
    
    # Add the text and HTML parts to the child container.
    msg_body.attach(textpart)
    msg_body.attach(htmlpart)
    
    # Define the attachment part and encode it using MIMEApplication.
    att = MIMEApplication(open(ATTACHMENT, 'rb').read())
    
    # Add a header to tell the email client to treat this part as an attachment,
    # and to give the attachment a name.
    att.add_header('Content-Disposition','attachment',filename=os.path.basename(ATTACHMENT))
    
    # Attach the multipart/alternative child container to the multipart/mixed
    # parent container.
    msg.attach(msg_body)
    
    # Add the attachment to the parent container.
    msg.attach(att)
    
    # Print message
    print(msg.as_string())