Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add embedded image in emails in AWS SES service

I am trying to write a Java app which can send emails to specify emails. In the email i also want to attach some pic.

Please find my code below :-

public class AmazonSESSample {

    static final String FROM = "[email protected]";
    static final String TO = "[email protected]";
    static final String BODY = "This email was sent through Amazon SES by using the AWS SDK for Java. hello";
    static final String SUBJECT = "Amazon SES test (AWS SDK for Java)";

    public static void main(String[] args) throws IOException {
        Destination destination = new Destination().withToAddresses(new String[] { TO });
        Content subject = new Content().withData(SUBJECT);
        Message msg = new Message().withSubject(subject);
        // Include a body in both text and HTML formats
        //Content textContent = new Content().withData("Hello - I hope you're having a good day.");
        Content htmlContent = new Content().withData("<h2>Hi User,</h2>\n"
                + " <h3>Please find the ABC Association login details below</h3>\n"
                + " <img src=\"logo.png\" alt=\"Mountain View\">\n"
                + " Click <a href=\"http://google.com">here</a> to go to the association portal.\n"
                + " <h4>Association ID - 12345</h4>\n" + "  <h4>Admin UID - suny342</h4>\n"
                + " <h4>Password - poass234</h4>\n" + " Regards,\n" + " <br>Qme Admin</br>");
        Body body = new Body().withHtml(htmlContent);
        msg.setBody(body);
        SendEmailRequest request = new SendEmailRequest().withSource(FROM).withDestination(destination)
                .withMessage(msg);
        try {
            System.out.println("Attempting to send an email through Amazon SES by using the AWS SDK for Java...");
            AWSCredentials credentials = null;
            credentials = new BasicAWSCredentials("ABC", "CDF");
            try {
                // credentialsProvider.
            } catch (Exception e) {
                throw new AmazonClientException("Cannot load the credentials from the credential profiles file. "
                        + "Please make sure that your credentials file is at the correct "
                        + "location (/Users/iftekharahmedkhan/.aws/credentials), and is in valid format.", e);
            }
            AmazonSimpleEmailService client = AmazonSimpleEmailServiceClientBuilder.standard()
                    .withCredentials(new AWSStaticCredentialsProvider(credentials)).withRegion("us-west-2").build();
            client.sendEmail(request);
            System.out.println("Email sent!");
        } catch (Exception ex) {
            System.out.println("The email was not sent.");
            System.out.println("Error message: " + ex.getMessage());
        }
    }
}

The image is placed in the resource directory but it is not being embeded in the email. Can anyone please help.

like image 873
Hello Singh Avatar asked Feb 02 '18 16:02

Hello Singh


People also ask

How do you embed an image in HTML email?

There is no single way to include images in emails. The best practice is to upload the images to a directory on your server and then link them to your HTML email using full URL paths. It requires download from the external server and faces issues of getting blocked by most email clients.

Can SES send email with attachment?

To send emails with attachments, you can call the Amazon SES SendRawEmail API, or use the AWS Software Development Kits (SDKs) to compose and send the message programmatically. The message, with attachment(s), will appear in the recipient's email client where it can be viewed or saved to disk.

How do I send an email template using SES?

To create a template to send personalized email messages, use the CreateTemplate operation. The template can be used by any account authorized to send messages in the AWS Region to which the template is added. Amazon SES doesn't validate your HTML, so be sure that HtmlPart is valid before sending an email.


3 Answers

Instead of relative path, you'll need to use either an absolute public path to the image itself or a data URL. For example:

<img src=\"https://example.com/logo.png\" alt=\"Mountain View\" />

or

<img src=\"data:image/png;base64, {BASE64_ENCODED_DATA}\" alt=\"Mountain View\" />

EDIT

As of January 2020, Gmail still does not support base64 encoded images.

like image 189
Khalid T. Avatar answered Oct 28 '22 17:10

Khalid T.


The method posted by @sebagra works well.

In case of Python using boto3 and ses client, the way to set to set the Content-Disposition to inline is:

    att.add_header('Content-ID', '<myImage>')
    att.add_header('Content-Disposition', 'inline', filename=os.path.basename(IMAGE_PATH))

Full example based on the python example in the AWS docs:

    import os
    import boto3
    from botocore.exceptions import ClientError
    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.
    IMAGE_PATH = "path/to/myImage.png"
    
    # 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 new SES resource and specify a region.
    client = boto3.client('ses',region_name=AWS_REGION)
    
    # 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(IMAGE_PATH, 'rb').read())
    
    # Add a header to tell the email client to treat this part as an attachment,
    # and set an id and content disposition.
    att.add_header('Content-ID', '<myImage>')
    att.add_header('Content-Disposition', 'inline', filename=os.path.basename(IMAGE_PATH))
    
    # 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)

    try:
        response = client.send_raw_email(
            Source=SENDER,
            Destinations=[
                RECIPIENT
            ],
            RawMessage={
                'Data': msg.as_string(),
            }
        )
    # Display an error if something goes wrong. 
    except ClientError as e:
        print(e.response['Error']['Message'])
    else:
        print("Email sent! Message ID:"),
        print(response['MessageId'])

In case of using sesv2 the msg is built the same but the the api to use is send_email:

    ...
    client = boto3.client('sesv2',region_name=AWS_REGION)
    ...
    response = client.send_email(
        FromEmailAddress=SENDER,
        Destination={
            'ToAddresses': [
                RECIPIENT
            ]
        },
        Content={
            'Raw': {
                'Data': msg.as_string()
            }
        }
    )
    ...
like image 42
Santiago Marietti Avatar answered Oct 28 '22 17:10

Santiago Marietti


I was able to send an email using AWS SES with images that can be seen in the GMail client, by attaching the images to the message and using an inline disposition reference to them.

I used the code explained in the AWS docs to attach images to a MimeMessage, and then using the cid reference from the HTML to those images (as explained in this post answer).

First, we attach the images to the message adding a couple of specific attributes (Header and Disposition):

        MimeMultipart msg = new MimeMultipart("mixed");        
        DataSource fds = new FileDataSource("/path/to/my/image.png");
        att.setDataHandler(new DataHandler(fds));
        att.setFileName(fds.getName());         
        att.setHeader("Content-ID","<myImage>");
        att.setDisposition("inline; filename=\"image.png\"");
        msg.addBodyPart(att);

Note that the < and > in the Content-ID attribute must be present enclosing whatever id you choose (myImage in my example).

Then, in the HTML of the message body we just need to add the cid (content id) of each image:

<img src="cid:myImage">

For the full code, I pretty much used the AWS reference above (using same variable names), the only changes made were the ones of the setHeader and setDisposition methods.

like image 3
SebaGra Avatar answered Oct 28 '22 17:10

SebaGra