This post is about using Raspi to send email using secure SMTP server like Gmail. Especially useful when the user need to be alerted about some sensor or actuator event. As you will see below that you need to turn ON the less secure app access in gmail settings.
This can be annoying as Gmail will prompt and advice you to OFF the feature due to security reason, hence many people set up another gmail account just for Raspi to send alert emails.
And currently I have Raspbian Version 10 (Buster) installed and after 2 nights of trying, I found out that ssmtp is deprecated for Buster version OS. So the below ssmtp method is not successful even after doing the following steps:
- ON the less secure app access in gmail settings
- root setting change to postmaster
- UseTLS=YES and UseSTARTTLS=YES
- change hostname=raspberrypi
From this website (https://techrapiduk.blogspot.com/2017/04/send-email-on-raspberry-pi-with-msmtp.html), I found out that you can use MSMTP to send email from Raspi. And after trying, it WORKS. 🙂
==============The below SSMTP steps, up to Raspi logo, is the SSMTP method==========
1st you need to install ssmtp using the following command: sudo apt install ssmtp mailutils

If some components are not downloaded, you may need to do some updating. Key sudo apt-get update


After which sudo apt install ssmtp mailutils again.

Installation done.

Then navigate to the ssmtp folder(cd /etc/ssmtp), key more ssmtp.conf and set the email settings(your email address and password).


Then key in your email address(from), pw and the rest is the same as per picture. Remember that any user on the Raspi will be able to see your password. So you should adjust the file attributes as follows(after below pic):


Lastly you need to adjust your gmail security setting by choosing ‘ON’ for ‘Allow less secure apps’.
Remarks: The above SSMTP method does not work for Raspbian Buster

The following MSMTP sent email method works for Buster OS.↓
I learn about this method from this website ( https://techrapiduk.blogspot.com/2017/04/send-email-on-raspberry-pi-with-msmtp.html )
Adjust your gmail security setting by choosing ‘ON’ for ‘Allow less secure apps.
Install MSMTP and ca-certificates, key following in terminal:
sudo apt-get install msmtp ca-certificates
After installation completion, screen shot:

Configure MSMTP:
Key the following in terminal:
cd /etc
sudo touch msmtprc sudo nano msmtprc
You will see a blank screen with some DOS command at the bottom:

Key the following setting into the screen, then press Ctrl X , follow by ‘Y’ when ask whether to save settings. ‘ username@gmail.com ‘ is your ‘From’ email and ‘ thepassword ‘ is your email pw.
account default host smtp.gmail.com port 587 logfile /tmp/msmtp.log tls on tls_starttls on tls_trust_file /etc/ssl/certs/ca-certificates.crt auth login user username@gmail.com password thepassword from First Last Name account account2
Testing: Send an email
Key the following in the terminal:
echo -e "Subject: Test Mail\r\n\r\nThis is a test mail" |msmtp --debug --from=default -t username@gmail.com
‘ username@gmail.com ‘ is the destination email address

Finally, email received. 🙂

Combining Motion Detection and Sending Email alerts
Ok, now we shall use the ‘Raspi Camera with motion detection’ project together with sending email via Raspi. Previously we sent the email via terminal, now we wrote a python function inside the ‘motion detection and recording’ script. So when motion is detected, the Raspi cam will record a 5 sec video and also send an email alert to my email. See below:
from picamera.array import PiRGBArray # Generates a 3D RGB array
from picamera import PiCamera # Provides a Python interface for the RPi Camera Module
import time # Provides time-related functions
from time import sleep
import datetime
import cv2 # OpenCV library
import numpy as np # Import NumPy library
import datetime
import os
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
def sendEmail():
email_user = "xxxxxxxxxxxxxx@gmail.com"
email_password = "xxxxxxxxxxxx"
email_send = "xxxxxxxxxxx@yahoo.com"
subject = "Test email from pi"
msg = MIMEMultipart()
msg["From"] = email_user
msg["To"] = email_send
msg["Subject"] = subject
body = "Hi there, motion detected. Sending this email from Raspy!"
msg.attach(MIMEText(body,"plain"))
text = msg.as_string()
server = smtplib.SMTP("smtp.gmail.com",587)
server.starttls()
server.login(email_user,email_password)
server.sendmail(email_user,email_send,text)
server.quit()
# Initialize the camera
camera = PiCamera()
camera.rotation = 180
# Set the camera resolution
camera.resolution = (640, 480)
#camera.resolution = (1280, 720)
#camera.resolution = (1640, 922)
#camera.resolution = (3280, 2464)
# Set the number of frames per second
#camera.framerate = 30
#camera.framerate = 60
camera.framerate = 30
# Generates a 3D RGB array and stores it in rawCapture
raw_capture = PiRGBArray(camera, size=(640, 480))
#raw_capture = PiRGBArray(camera, size=(1280, 720))
#raw_capture = PiRGBArray(camera, size=(1640, 922))
#raw_capture = PiRGBArray(camera, size=(3280, 2464))
# Create the background subtractor object
# Feel free to modify the history as you see fit.
#back_sub = cv2.createBackgroundSubtractorMOG2(history=150,
#varThreshold=25, detectShadows=True)
back_sub = cv2.createBackgroundSubtractorMOG2(history=25,
varThreshold=20, detectShadows=True)
# Wait a certain number of seconds to allow the camera time to warmup
time.sleep(0.1)
# Create kernel for morphological operation. You can tweak
# the dimensions of the kernel.
# e.g. instead of 20, 20, you can try 30, 30
kernel = np.ones((20,20),np.uint8)
# Capture frames continuously from the camera
for frame in camera.capture_continuous(raw_capture, format="bgr", use_video_port=True):
# Grab the raw NumPy array representing the image
image = frame.array
# Convert to foreground mask
fg_mask = back_sub.apply(image)
# Close gaps using closing
fg_mask = cv2.morphologyEx(fg_mask,cv2.MORPH_CLOSE,kernel)
# Remove salt and pepper noise with a median filter
fg_mask = cv2.medianBlur(fg_mask,5)
# If a pixel is less than ##, it is considered black (background).
# Otherwise, it is white (foreground). 255 is upper limit.
# Modify the number after fg_mask as you see fit.
_, fg_mask = cv2.threshold(fg_mask, 127, 255, cv2.THRESH_BINARY)
# Find the contours of the object inside the binary image
contours, hierarchy = cv2.findContours(fg_mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)[-2:]
areas = [cv2.contourArea(c) for c in contours]
# If there are no countours
if len(areas) < 1:
# Display the resulting frame
cv2.imshow('Frame',image)
# Wait for keyPress for 1 millisecond
key = cv2.waitKey(1) & 0xFF
# Clear the stream in preparation for the next frame
raw_capture.truncate(0)
# If "q" is pressed on the keyboard,
# exit this loop
if key == ord("q"):
break
# Go to the top of the for loop
continue
else:
# Find the largest moving object in the image
max_index = np.argmax(areas)
# Draw the bounding box
cnt = contours[max_index]
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2)
# Draw circle in the center of the bounding box
x2 = x + int(w/2)
y2 = y + int(h/2)
cv2.circle(image,(x2,y2),4,(0,255,0),-1)
# Print the centroid coordinates (we'll use the center of the
# bounding box) on the image
text = "x: " + str(x2) + ", y: " + str(y2)
cv2.putText(image, text, (x2 - 10, y2 - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# Display the resulting frameq
cv2.imshow("Frame",image)
#Record.....
#while w > 500 and h > 500: #doesn't work
while h > 350:
date = datetime.datetime.now().strftime("%d-%m-%Y_%H-%M-%S")
camera.start_recording('/mnt/mydisk/'+date+'.h264')
sleep(5)
camera.stop_recording()
sendEmail()
break
# Wait for keyPress for 1 millisecond
key = cv2.waitKey(1) & 0xFF
# Clear the stream in preparation for the next frame
raw_capture.truncate(0)
# If "q" is pressed on the keyboard,
# exit this loop
if key == ord("q"):
break
##Delete video files which are more than 7 days old
path = '/mnt/mydisk/'
today = datetime.datetime.today()#gets current time
os.chdir(path) #changing path to current path(same as cd command)
#Iterate thru files
for root, directories, files in os.walk(path,topdown=False):
for name in files:
#last modified time
timeStamp = os.stat(os.path.join(root, name))[8]
filetime = datetime.datetime.fromtimestamp(timeStamp) - today
#check if recirdings file is more than 7 days old, if yes then delete them
if filetime.days <= -7:
print(os.path.join(root, name), filetime.days)
os.remove(os.path.join(root, name))
# Close down windows
cv2.destroyAllWindows()
The sendEmail function is at line 16 and the function call is at line 151. Below is the email alert that I received in my yahoo mailbox.

That’s it folks, hope everyone enjoyed this geeky post. 😉
I personally feel that sending email alerts is too troublesome and not so practical. You have to set the gmail ‘allow less secure apps’ thingy, and upon setting, you will receive a few alerts and security emails from Google. And security wise is not advisable as your pw is in the script.
Therefore I will have another post where Raspi or Arduino will sent SMS alert instead of email. I think SMS alert is more practical. Right?