Home > Software engineering >  Send SVG image content to email as HTML using boto3
Send SVG image content to email as HTML using boto3

Time:05-13

I want to send SVG content (without saved file) as HTML to Outlook email address. This SVG content works fine in browser showing a circle image, however sending it via boto3.client to Outlook email results in empty mail. Why? Any suggestions appreciated.

import io
import json
import boto3
from botocore.exceptions import ClientError

SENDER = "Name1 LastName1 <[email protected]>"
RECIPIENT = "Name2 LastName2 <[email protected]>"
AWS_REGION = "us-east-1"
SUBJECT = "something"

svg = """
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg> 
"""

BODY_HTML = f"""<html>
<body>
{svg}
</body>
</html>
            """ 

CHARSET = "UTF-8"

client = boto3.client('ses',region_name=AWS_REGION)

try:
    response = client.send_email(
        Destination={
            'ToAddresses': [
                RECIPIENT
            ],
        },
        Message={
            'Body': {
                'Html': {
                    'Charset': CHARSET,
                    'Data': BODY_HTML
                }
            },
            'Subject': {
                'Charset': CHARSET,
                'Data': SUBJECT
            },
        },
        Source=SENDER
    )   
except ClientError as e:
    print(e.response['Error']['Message'])
else:
    print("Email sent! Message ID:"),
    print(response['MessageId'])

CodePudding user response:

SVG graphics are widely supported in web browsers but not all email programs know what to do with these new images. In case of Outlook you need to export the file to any image file format like PNG or JPEG and then attach it to the mail item. Then in the message body you can refer to use using a special syntax with a cid: prefix. Also you need to set the PR_ATTACH_CONTENT_ID MAPI property (DASL name "http://schemas.microsoft.com/mapi/proptag/0x3712001F") using the Attachment.PropertyAccessor.SetProperty method and refer that attachment through the src attribute that matches the value of PR_ATTACH_CONTENT_ID set on the attachment. PR_ATTACH_CONTENT_ID corresponds to the Content-ID MIME header when the message is sent.

attachment = MailItem.Attachments.Add("c:\temp\MyPicture.jpg")
attachment.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001F", "YourImageId")
MailItem.HTMLBody = "<html><body>Test image <img src=""cid:YourImageId""></body></html>"

CodePudding user response:

I've found a solution. Used send_raw_email and MIMEImage, cid from MIMEImage was used to insert image data in html body. Updated code as follows:

from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import json
import boto3
from botocore.exceptions import ClientError

SENDER = "Name1 LastName1 <[email protected]>"
RECIPIENT = "Name2 LastName2 <[email protected]>"
AWS_REGION = "us-east-1"
SUBJECT = "something"

png_data = image_bytes()

CHARSET = "utf-8"

client = boto3.client('ses',region_name=AWS_REGION)

msg = MIMEMultipart('mixed')

msg['Subject'] = SUBJECT 
msg['From'] = SENDER 
msg['To'] = RECIPIENT

img = MIMEImage(png_data, 'png')
img.add_header("Content-Type", "image/png", name="some_name.png")
img.add_header("Content-Disposition", "inline", filename="some_name.png")
img.add_header('Content-Id', 'some_cid_name')
img.add_header('Content-Transfer-Encoding', 'base64')

BODY_HTML = '<img src="cid:some_cid_name"/>'

email_body= MIMEText(BODY_HTML.encode(CHARSET), 'html', CHARSET)
msg.attach(email_body)

try:
    #Provide the contents of the email.
    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'])
  • Related