Search code examples
pythonflask-mail

Cannot add file as inline attachment python flask using CID


I have spent hours searching for a solution to no avail. I am trying to include some images in automatically generated emails, and have come up against some problems. I Cannot include the actual url as gmail blocks the images totally, so I am trying to send as attachments and then use Cids to reference the attachments. The issue is I haven't found a way to do this. Any help would be ace.

I am running python 3.6 on with Apache2 on an Ubuntu server. I have tried encoding images in base64 but that didnt work at all. the images in the email simply didnt show up.

def createVoucher(email, expiry):
    voucherId = str(uuid.uuid4())
    email = email
    value = 1
    expiryDate = expiry
    redeemed = 1
    connection = mysql.get_db()
    cursor = connection.cursor()
    cursor.execute("INSERT INTO vouchers (VoucherID, Value, ExpiryDate, Redeemed, Email) VALUES (%s,%s,%s,%s,%s)", (voucherId, value, expiryDate, redeemed, email))
    msgBody = render_template('admin/eVoucherEmail.html', voucherId=voucherId, expiry=expiry)
    msg = Message('New Sunday Funday eVoucher Received', sender = MAIL_USERNAME, recipients = [email])
    msg.html = msgBody
    with app.open_resource("static/img/Facebook.jpg") as fp:
        msg.attach("Facebook.jpg", "image/jpg", fp.read())
    mail.send(msg)    
    connection.commit()

So the code posted works fine attaching the file, it's just assigning a content id that I can use where I am struggling.


Solution

  • Here's how I insert an inline jpg using flask_mail.

    versions: python=3.7.6, flask=1.1.2, and flask-mail=0.9.1

    The "disposition" in message.attach needs to be "inline", and the html for the img should contain "cid:my_cid" as the src.

    import uuid
    from flask import Flask
    from flask_mail import Mail, Message
    from pathlib import Path
    
    app = Flask(__name__)
    app.config.update(
        MAIL_SERVER='smtp.gmail.com', MAIL_PORT=465, MAIL_USE_SSL=True,
        MAIL_USERNAME="[email protected]", MAIL_PASSWORD="myfakepw54858939")
    flask_mail = Mail(app)
    
    def test_send_voucher():
        to_addr = "[email protected]"
        expiry = "29 February"
        voucher_png_path = Path(__file__).parent / "static/Facebook.jpg"
        sendVoucherEmail(app, to_addr, expiry, voucher_png_path)
    
    def sendVoucherEmail(app: Flask, to_addr: str, expiry: str, voucher_png_path: Path):
        voucher_id = str(uuid.uuid4())
        html = f"""<html><head></head><body>
        <p>Congratulations on your voucher!<br>Your voucher code is {voucher_id}. 
        The offer expires on {expiry}.<br>
        <img src="cid:voucher_png" width=200>
        </p></body></html>"""
        with app.app_context():
            mail = Mail(app)
            message: Message = Message(subject="my subject", sender="[email protected]", 
                                       recipients=[to_addr], html=html)
            with app.open_resource(voucher_png_path) as fp:
                message.attach(filename="myfilename.png", content_type="image/png", data=fp.read(), 
                               disposition="inline", headers=[['Content-ID', '<voucher_png>']])
            mail.send(message)
    

    This example successfully sent an email via gmail, with an inline image "Facebook.jpg," as in the original question.

    screenshot of received email