We have already covered using a Raspberry Pi and Python to send an email containing basic text – but what if you wanted to attach a picture instead? In this tutorial we are going to adapt our code from our basic email tutorial to allow picture attachments to be sent. We will use a Raspberry Pi Camera to capture an image and send the photo out as soon as the button is pressed. Going forwards, this code chunk could be adapted to send when your cookie alarm is tripped, at a specific time of day, or whatever other condition you come up with!
There are a lot of different operating systems out there for the Raspberry Pi, so we are going to focus on the most popular: Raspbian. We are using the version dated: 2019-7-10 (Pi 4 Compatible) available from the Raspberry Pi Foundations’ Download Page. You don’t need to use the Raspberry Pi 4, any Raspberry Pi will do. However, deviating from the recommended operating system version may result in different / additional steps so if you are very new to this, we recommend following the tutorial exactly.
This tutorial requires several items:
We are going to reuse / modify our existing code from the last tutorial. We are going to add the library for the Pi Camera, take a picture, save it, and send that file as an attachment in our email. This means we need to modify our email sender class as well – this sounds complicated, but it is actually quite easy. Just a reminder: Do not use your normal email address – the email address and password are stored in plain text in your code!
import smtplib
import RPi.GPIO as GPIO
import time
#Email Variables
SMTP_SERVER = 'smtp.gmail.com' #Email Server (don't change!)
SMTP_PORT = 587 #Server Port (don't change!)
GMAIL_USERNAME = 'youremail@email.com' #change this to match your gmail account
GMAIL_PASSWORD = 'yourPassword' #change this to match your gmail password
#Set GPIO pins to use BCM pin numbers
GPIO.setmode(GPIO.BCM)
#Set digital pin 17(BCM) to an input and enable the pullup
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Event to detect button press
GPIO.add_event_detect(17, GPIO.FALLING)
class Emailer:
def sendmail(self, recipient, subject, content):
#Create Headers
headers = ["From: " + GMAIL_USERNAME, "Subject: " + subject, "To: " + recipient,
"MIME-Version: 1.0", "Content-Type: text/html"]
headers = "\r\n".join(headers)
#Connect to Gmail Server
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
#Login to Gmail
session.login(GMAIL_USERNAME, GMAIL_PASSWORD)
#Send Email & Exit
session.sendmail(GMAIL_USERNAME, recipient, headers + "\r\n\r\n" + content)
session.quit
sender = Emailer()
while True:
if GPIO.event_detected(17):
sendTo = 'anotheremail@email.com'
emailSubject = "Button Press Detected!"
emailContent = "The button has been pressed at: " + time.ctime()
sender.sendmail(sendTo, emailSubject, emailContent)
print("Email Sent")
time.sleep(0.1)
Our code from the last tutorial worked by sending an email when a button connected to GPIO17 was pressed.
import smtplib
import RPi.GPIO as GPIO
import time
from picamera import PiCamera
#Email Variables
SMTP_SERVER = 'smtp.gmail.com' #Email Server (don't change!)
SMTP_PORT = 587 #Server Port (don't change!)
GMAIL_USERNAME = 'youremail@email.com' #change this to match your gmail account
GMAIL_PASSWORD = 'yourPassword' #change this to match your gmail password
#Set GPIO pins to use BCM pin numbers
GPIO.setmode(GPIO.BCM)
#Set digital pin 17(BCM) to an input and enable the pullup
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Event to detect button press
GPIO.add_event_detect(17, GPIO.FALLING)
class Emailer:
def sendmail(self, recipient, subject, content):
#Create Headers
headers = ["From: " + GMAIL_USERNAME, "Subject: " + subject, "To: " + recipient,
"MIME-Version: 1.0", "Content-Type: text/html"]
headers = "\r\n".join(headers)
#Connect to Gmail Server
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
#Login to Gmail
session.login(GMAIL_USERNAME, GMAIL_PASSWORD)
#Send Email & Exit
session.sendmail(GMAIL_USERNAME, recipient, headers + "\r\n\r\n" + content)
session.quit
sender = Emailer()
while True:
if GPIO.event_detected(17):
sendTo = 'anotheremail@email.com'
emailSubject = "Button Press Detected!"
emailContent = "The button has been pressed at: " + time.ctime()
sender.sendmail(sendTo, emailSubject, emailContent)
print("Email Sent")
time.sleep(0.1)
We are going to assume you have the camera plugged in, and the camera enabled in your Pi settings. If you have not used the camera before, we recommend having a look at the Raspberry Pi Foundation’s Camera Tutorial first.
Start by importing the PiCamera.
import smtplib
import RPi.GPIO as GPIO
import time
from picamera import PiCamera
#Camera Settings
camera = PiCamera()
camera.resolution = (2592, 1944)
camera.framerate = 15
#Email Variables
SMTP_SERVER = 'smtp.gmail.com' #Email Server (don't change!)
SMTP_PORT = 587 #Server Port (don't change!)
GMAIL_USERNAME = 'youremail@email.com' #change this to match your gmail account
GMAIL_PASSWORD = 'yourPassword' #change this to match your gmail password
#Set GPIO pins to use BCM pin numbers
GPIO.setmode(GPIO.BCM)
#Set digital pin 17(BCM) to an input and enable the pullup
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Event to detect button press
GPIO.add_event_detect(17, GPIO.FALLING)
class Emailer:
def sendmail(self, recipient, subject, content):
#Create Headers
headers = ["From: " + GMAIL_USERNAME, "Subject: " + subject, "To: " + recipient,
"MIME-Version: 1.0", "Content-Type: text/html"]
headers = "\r\n".join(headers)
#Connect to Gmail Server
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
#Login to Gmail
session.login(GMAIL_USERNAME, GMAIL_PASSWORD)
#Send Email & Exit
session.sendmail(GMAIL_USERNAME, recipient, headers + "\r\n\r\n" + content)
session.quit
sender = Emailer()
while True:
if GPIO.event_detected(17):
sendTo = 'anotheremail@email.com'
emailSubject = "Button Press Detected!"
emailContent = "The button has been pressed at: " + time.ctime()
sender.sendmail(sendTo, emailSubject, emailContent)
print("Email Sent")
time.sleep(0.1)
Next, we are going to set the image size. We are going to use the 5MP Image size as it works with both V1 and V2 Pi Camera modules, along with any other OVR5647 based cameras for the Raspberry Pi. Since we are setting the camera capture size above 1080p, we also need to define the frame rate for it to work.
import smtplib
import RPi.GPIO as GPIO
import time
from picamera import PiCamera
#Camera Settings
camera = PiCamera()
camera.resolution = (2592, 1944)
camera.framerate = 15
#Email Variables
SMTP_SERVER = 'smtp.gmail.com' #Email Server (don't change!)
SMTP_PORT = 587 #Server Port (don't change!)
GMAIL_USERNAME = 'youremail@email.com' #change this to match your gmail account
GMAIL_PASSWORD = 'yourPassword' #change this to match your gmail password
#Set GPIO pins to use BCM pin numbers
GPIO.setmode(GPIO.BCM)
#Set digital pin 17(BCM) to an input and enable the pullup
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Event to detect button press
GPIO.add_event_detect(17, GPIO.FALLING)
class Emailer:
def sendmail(self, recipient, subject, content):
#Create Headers
headers = ["From: " + GMAIL_USERNAME, "Subject: " + subject, "To: " + recipient,
"MIME-Version: 1.0", "Content-Type: text/html"]
headers = "\r\n".join(headers)
#Connect to Gmail Server
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
#Login to Gmail
session.login(GMAIL_USERNAME, GMAIL_PASSWORD)
#Send Email & Exit
session.sendmail(GMAIL_USERNAME, recipient, headers + "\r\n\r\n" + content)
session.quit
sender = Emailer()
while True:
if GPIO.event_detected(17):
image = '/home/pi/Desktop/image.jpg'
camera.capture(image)
sendTo = 'anotheremail@email.com'
emailSubject = "Button Press Detected!"
emailContent = "The button has been pressed at: " + time.ctime()
sender.sendmail(sendTo, emailSubject, emailContent)
print("Email Sent")
time.sleep(0.1)
To take a photo is actually very simple with the PiCamera Module. We are going to define our image name and file location. Next, we capture the image with the camera.capture command. The camera will then capture the image and save it at the defined location “/home/pi/Desktop/” as “image.jpg”. Since we have defined the name and location like this, every time we take a new photo it will overwrite the last image. A dynamic image name could be used if you want to keep each image – however we wont go into that in this tutorial.
import smtplib
import RPi.GPIO as GPIO
import time
from picamera import PiCamera
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
#Camera Settings
camera = PiCamera()
camera.resolution = (2592, 1944)
camera.framerate = 15
#Email Variables
SMTP_SERVER = 'smtp.gmail.com' #Email Server (don't change!)
SMTP_PORT = 587 #Server Port (don't change!)
GMAIL_USERNAME = 'youremail@email.com' #change this to match your gmail account
GMAIL_PASSWORD = 'yourPassword' #change this to match your gmail password
#Set GPIO pins to use BCM pin numbers
GPIO.setmode(GPIO.BCM)
#Set digital pin 17(BCM) to an input and enable the pullup
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Event to detect button press
GPIO.add_event_detect(17, GPIO.FALLING)
class Emailer:
def sendmail(self, recipient, subject, content):
#Create Headers
headers = ["From: " + GMAIL_USERNAME, "Subject: " + subject, "To: " + recipient,
"MIME-Version: 1.0", "Content-Type: text/html"]
headers = "\r\n".join(headers)
#Connect to Gmail Server
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
#Login to Gmail
session.login(GMAIL_USERNAME, GMAIL_PASSWORD)
#Send Email & Exit
session.sendmail(GMAIL_USERNAME, recipient, headers + "\r\n\r\n" + content)
session.quit
sender = Emailer()
while True:
if GPIO.event_detected(17):
image = '/home/pi/Desktop/image.jpg'
camera.capture(image)
sendTo = 'anotheremail@email.com'
emailSubject = "Button Press Detected!"
emailContent = "The button has been pressed at: " + time.ctime()
sender.sendmail(sendTo, emailSubject, emailContent)
print("Email Sent")
time.sleep(0.1)
It was a lot easier to send a plain text email – we need a little more help to send an email that has text content and a file attachment. We will need the MIME Libraries to help create this type of message.
import smtplib
import RPi.GPIO as GPIO
import time
from picamera import PiCamera
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
#Camera Settings
camera = PiCamera()
camera.resolution = (2592, 1944)
camera.framerate = 15
#Email Variables
SMTP_SERVER = 'smtp.gmail.com' #Email Server (don't change!)
SMTP_PORT = 587 #Server Port (don't change!)
GMAIL_USERNAME = 'youremail@email.com' #change this to match your gmail account
GMAIL_PASSWORD = 'yourPassword' #change this to match your gmail password
#Set GPIO pins to use BCM pin numbers
GPIO.setmode(GPIO.BCM)
#Set digital pin 17(BCM) to an input and enable the pullup
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Event to detect button press
GPIO.add_event_detect(17, GPIO.FALLING)
class Emailer:
def sendmail(self, recipient, subject, content, image):
#Create Headers
headers = ["From: " + GMAIL_USERNAME, "Subject: " + subject, "To: " + recipient,
"MIME-Version: 1.0", "Content-Type: text/html"]
headers = "\r\n".join(headers)
#Connect to Gmail Server
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
#Login to Gmail
session.login(GMAIL_USERNAME, GMAIL_PASSWORD)
#Send Email & Exit
session.sendmail(GMAIL_USERNAME, recipient, headers + "\r\n\r\n" + content)
session.quit
sender = Emailer()
while True:
if GPIO.event_detected(17):
image = '/home/pi/Desktop/image.jpg'
camera.capture(image)
sendTo = 'anotheremail@email.com'
emailSubject = "Button Press Detected!"
emailContent = "The button has been pressed at: " + time.ctime()
sender.sendmail(sendTo, emailSubject, emailContent, image)
print("Email Sent")
time.sleep(0.1)
We need to update our Emailer Class to accept an image file location in addition to our existing arguments.
import smtplib
import RPi.GPIO as GPIO
import time
from picamera import PiCamera
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
#Camera Settings
camera = PiCamera()
camera.resolution = (2592, 1944)
camera.framerate = 15
#Email Variables
SMTP_SERVER = 'smtp.gmail.com' #Email Server (don't change!)
SMTP_PORT = 587 #Server Port (don't change!)
GMAIL_USERNAME = 'youremail@email.com' #change this to match your gmail account
GMAIL_PASSWORD = 'yourPassword' #change this to match your gmail password
#Set GPIO pins to use BCM pin numbers
GPIO.setmode(GPIO.BCM)
#Set digital pin 17(BCM) to an input and enable the pullup
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Event to detect button press
GPIO.add_event_detect(17, GPIO.FALLING)
class Emailer:
def sendmail(self, recipient, subject, content, image):
#Create Headers
emailData = MIMEMultipart()
emailData['Subject'] = subject
emailData['To'] = recipient
emailData['From'] = GMAIL_USERNAME
#Connect to Gmail Server
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
#Login to Gmail
session.login(GMAIL_USERNAME, GMAIL_PASSWORD)
#Send Email & Exit
session.sendmail(GMAIL_USERNAME, recipient, headers + "\r\n\r\n" + content)
session.quit
sender = Emailer()
while True:
if GPIO.event_detected(17):
image = '/home/pi/Desktop/image.jpg'
camera.capture(image)
sendTo = 'anotheremail@email.com'
emailSubject = "Button Press Detected!"
emailContent = "The button has been pressed at: " + time.ctime()
sender.sendmail(sendTo, emailSubject, emailContent, image)
print("Email Sent")
time.sleep(0.1)
Our new email is constructed as a MIME Multipart Object – so we will have to scrap our old headers and do this a little differently. We will create the overall email with its headers and then add our text and image components before sending. Start by removing the old headers code and replace with this new code.
import smtplib
import RPi.GPIO as GPIO
import time
from picamera import PiCamera
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
#Camera Settings
camera = PiCamera()
camera.resolution = (2592, 1944)
camera.framerate = 15
#Email Variables
SMTP_SERVER = 'smtp.gmail.com' #Email Server (don't change!)
SMTP_PORT = 587 #Server Port (don't change!)
GMAIL_USERNAME = 'youremail@email.com' #change this to match your gmail account
GMAIL_PASSWORD = 'yourPassword' #change this to match your gmail password
#Set GPIO pins to use BCM pin numbers
GPIO.setmode(GPIO.BCM)
#Set digital pin 17(BCM) to an input and enable the pullup
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Event to detect button press
GPIO.add_event_detect(17, GPIO.FALLING)
class Emailer:
def sendmail(self, recipient, subject, content, image):
#Create Headers
emailData = MIMEMultipart()
emailData['Subject'] = subject
emailData['To'] = recipient
emailData['From'] = GMAIL_USERNAME
#Attach our text data
emailData.attach(MIMEText(content))
#Connect to Gmail Server
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
#Login to Gmail
session.login(GMAIL_USERNAME, GMAIL_PASSWORD)
#Send Email & Exit
session.sendmail(GMAIL_USERNAME, recipient, headers + "\r\n\r\n" + content)
session.quit
sender = Emailer()
while True:
if GPIO.event_detected(17):
image = '/home/pi/Desktop/image.jpg'
camera.capture(image)
sendTo = 'anotheremail@email.com'
emailSubject = "Button Press Detected!"
emailContent = "The button has been pressed at: " + time.ctime()
sender.sendmail(sendTo, emailSubject, emailContent, image)
print("Email Sent")
time.sleep(0.1)
Attaching text is very simple – we don’t need to do anything other than attach our Text.
import smtplib
import RPi.GPIO as GPIO
import time
from picamera import PiCamera
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
#Camera Settings
camera = PiCamera()
camera.resolution = (2592, 1944)
camera.framerate = 15
#Email Variables
SMTP_SERVER = 'smtp.gmail.com' #Email Server (don't change!)
SMTP_PORT = 587 #Server Port (don't change!)
GMAIL_USERNAME = 'youremail@email.com' #change this to match your gmail account
GMAIL_PASSWORD = 'yourPassword' #change this to match your gmail password
#Set GPIO pins to use BCM pin numbers
GPIO.setmode(GPIO.BCM)
#Set digital pin 17(BCM) to an input and enable the pullup
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Event to detect button press
GPIO.add_event_detect(17, GPIO.FALLING)
class Emailer:
def sendmail(self, recipient, subject, content, image):
#Create Headers
emailData = MIMEMultipart()
emailData['Subject'] = subject
emailData['To'] = recipient
emailData['From'] = GMAIL_USERNAME
#Attach our text data
emailData.attach(MIMEText(content))
#Create our Image Data from the defined image
imageData = MIMEImage(open(image, 'rb').read(), 'jpg')
imageData.add_header('Content-Disposition', 'attachment; filename="image.jpg"')
emailData.attach(imageData)
#Connect to Gmail Server
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
#Login to Gmail
session.login(GMAIL_USERNAME, GMAIL_PASSWORD)
#Send Email & Exit
session.sendmail(GMAIL_USERNAME, recipient, headers + "\r\n\r\n" + content)
session.quit
sender = Emailer()
while True:
if GPIO.event_detected(17):
image = '/home/pi/Desktop/image.jpg'
camera.capture(image)
sendTo = 'anotheremail@email.com'
emailSubject = "Button Press Detected!"
emailContent = "The button has been pressed at: " + time.ctime()
sender.sendmail(sendTo, emailSubject, emailContent, image)
print("Email Sent")
time.sleep(0.1)
Attaching an image takes a little extra configuration. To ensure the file arrives on the other side with the correct file name and file extension we need to add a header to this component. Without this, the file appears to the recipient as a .dat file – not very practical.
import smtplib
import RPi.GPIO as GPIO
import time
from picamera import PiCamera
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
#Camera Settings
camera = PiCamera()
camera.resolution = (2592, 1944)
camera.framerate = 15
#Email Variables
SMTP_SERVER = 'smtp.gmail.com' #Email Server (don't change!)
SMTP_PORT = 587 #Server Port (don't change!)
GMAIL_USERNAME = 'youremail@email.com' #change this to match your gmail account
GMAIL_PASSWORD = 'yourPassword' #change this to match your gmail password
#Set GPIO pins to use BCM pin numbers
GPIO.setmode(GPIO.BCM)
#Set digital pin 17(BCM) to an input and enable the pullup
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#Event to detect button press
GPIO.add_event_detect(17, GPIO.FALLING)
class Emailer:
def sendmail(self, recipient, subject, content, image):
#Create Headers
emailData = MIMEMultipart()
emailData['Subject'] = subject
emailData['To'] = recipient
emailData['From'] = GMAIL_USERNAME
#Attach our text data
emailData.attach(MIMEText(content))
#Create our Image Data from the defined image
imageData = MIMEImage(open(image, 'rb').read(), 'jpg')
imageData.add_header('Content-Disposition', 'attachment; filename="image.jpg"')
emailData.attach(imageData)
#Connect to Gmail Server
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
#Login to Gmail
session.login(GMAIL_USERNAME, GMAIL_PASSWORD)
#Send Email & Exit
session.sendmail(GMAIL_USERNAME, recipient, emailData.as_string())
session.quit
sender = Emailer()
while True:
if GPIO.event_detected(17):
image = '/home/pi/Desktop/image.jpg'
camera.capture(image)
sendTo = 'anotheremail@email.com'
emailSubject = "Button Press Detected!"
emailContent = "The button has been pressed at: " + time.ctime()
sender.sendmail(sendTo, emailSubject, emailContent, image)
print("Email Sent")
time.sleep(0.1)
The last thing we need to do is update the send command.
With the code above (and your credentials entered) pressing the button will now take a photo and email it to whatever email address you have entered. Test it out by pressing the button – the email should show up in just a moment!
Going forwards, this code can be modified to take a picture and email it out based on whatever pre-defined conditions you wish to set up. The picture size and other camera attributes could also be changed to better suit your application.
3 thoughts on “Sending An Email With Attached Photo Using Python And The Raspberry Pi”
William @ BC Robotics
Hi Hans!
You should be able to define the filename in Line 45 without any further changes to the code. That filename is just a string – it can be constructed on the fly as well. Something along the lines of:
[python]
current_date = datetime.date.today()
generatedFilename = "image-" + current_date + ".jpg"
[/python]
and line 45 would simply be
[python]imageData.add_header(‘Content-Disposition’, ‘attachment; filename=generatedFilename’)[/python]
Gary
Thank you so much for the easy to follow instructions. It is a refreshing inspirational pleasure to have a tutorial that really works ! I intend to learn more about the RPI and the smtplib, and how to use it. Our robotics club meets at our local library, and this project will be effective demonstration for our March 2022 Raspberry Pi Jam.
jimin
Hi, can I do this with raspberry pi pico?