Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Adding Email Attachments With smtplib

As mails only accept text formats, you’ll learn how to encode binary data to send it as email attachment. In this case this will be a picture.

00:00 Now that you know how to send emails with HTML formatting, it’s time to learn how to add attachments. Since email is designed to work with text data and attachments are binary, you need to treat these a little bit differently.

00:13 You’re going to learn how to encode your attachments to base64 before sending them over the air. This is going to take a couple more imports, so up here, go ahead and add email.

00:26 And then from email import encoders. This is going to help with the encoding of the attachment. Now to work with the MIME standard, you’re going to from email.mime.base import MIMEBase.

00:48 MIMEBase is similar to MIMEText. It’s a little bit more general. MIMEText is geared towards the body information, so it contains some of the headers to work with the SMTP protocol.

00:59 MIMEBase is where we’re going to put the attachment. Okay. We can leave just about everything else the same. After these parts here, I’m just going to make a variable called filename and set this equal to 'cookie.jpg'.

01:19 This is because I have a picture of Cookie in the same directory as my script and this is what I want to attach to my email. So, like other files, I’m going to do a with open(), pass in filename, read this as a binary, and we’ll just call this as attachment.

01:39 Now to differentiate this from the body information, I’m just going to call this part_a, set this equal to MIMEBase(), and then pass in 'application' and 'octet-stream'.

01:59 And this prepares that MIMEBase to take the attachment. Now with part_a, set the payload

02:11 to attachment.read(). Okay. Now using that encoders library, you’re just going to encode as base64 and pass in part_a.

02:27 The last thing you need to do before you can attach this to the email is to add some additional header information. So call the .add_header() method,

02:39 pass in 'Content-Disposition', and then with some f-string formatting,

02:50 just say f'attachment; filename= {}', and pass in that filename. All right! So you’ve now added a filename, you’ve opened the file, read it as an attachment, created a new MIMEBase item, and then passed that attachment into it.

03:17 You then encoded that into base64 and added some header information, and now you can go ahead and with that message from earlier, you can just .attach(part_a), just like that. Okay!

03:31 Let’s save that. Just to make it different, let me go up here and change the subject of the email to 'Cookie!'.

03:43 Let’s save that, open up the terminal, and run the script.

03:57 No errors, so that’s always a good sign. Let’s head over to the inbox, and let’s see! Here it is. Scroll down and there’s the picture of my cat Cookie. Cool!

04:10 So now you can add files as attachments to the emails before you send them. In the next video, you’re going to learn how to use a CSV file to send multiple personalized emails out with a single script. Thanks for watching.

Avatar image for KatMac

KatMac on April 22, 2021

Hi

I copied a small logo into the same folder as my code for this chapter townofbauline.ca/logo.jpg

The email was successfully sent and the logo file was attached. However the logo displayed embedded in the body of my email as ‘noname’ with no file extension.

Can’t figure out what is wrong here.

with open(filename, "rb") as attachment:
    part_a = MIMEBase("application", "octet-stream")
    part_a.set_payload(attachment.read())

encoders.encode_base64(part_a)

part_a.add_header(
    "Content-Disposition",
    f"attachment: filename={filename}"
)

message.attach(part1)
message.attach(part2)
message.attach(part_a)

context = ssl.create_default_context()

with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:
    server.login(sender, password)
    server.sendmail(sender, receiver, message.as_string())
Avatar image for KatMac

KatMac on April 23, 2021

Hi I figured it out. It was my typing. It now works

Become a Member to join the conversation.