Skip to main content

Raymii.org Logo (IEC resistor symbol)logo

Quis custodiet ipsos custodes?
Home | About | All pages | RSS Feed | Gopher

Send email with multiple inline images via bash with a loop

Published: 23-07-2018 | Author: Remy van Elst | Text only version of this article


Table of Contents


Recently I had a request from a user that whished to receive a scheduled emailwith two screenshots. The screenshots were automated via AutoIt on a networkshare, the user manually logged in every evening to check the pictures. Withbash and postfix/sendmail we can automate this process, the user now doesn'thave to login but can just check their email. There are a lot of snippets andguides to attach emails via the shell, but displaying multiple images inline asan HTML mail was something I had to figure out. You cannot embed the image inbase64 HTML because Outlook doesn't show that, you must use the Content-ID styleembed. Like UUENCODE, but more complicated. (The next step in this process withthe user is to automate the reason why they have to check those screenshotsevery night, that is something for another article)

If you like this article, consider sponsoring me by trying out a Digital OceanVPS. With this link you'll get $100 credit for 60 days). (referral link)

The script first fetches the images from a remote URL and places them on thefilesystem, in a date-structured folder for archival purposes. It thenconstructs the HTML email, appending the attachments as base64 encoded contentbelow the text part of the email.

Script

#!/bin/bash# date with hour and minute for in filenameCURDATE=$(date +%Y%m%dT%H%M)# date for folder nameFOLDERDATE=$(date +%Y%m%d)# path where files are stored for archivalSAVEPATH=/opt/monitoring/screenshots/$FOLDERDATEmkdir -p $SAVEPATH# declare the array with the images to mail, can be as many as you want.declare -A ATTS#filename without extension. Key = header, value is filename without extATTS["Screenshot 1, Most important"]="image1"ATTS["Screenshot 2, Some more info"]="image2"# extension must all be the sameEXT=".png"# loop over all images and download them locally$(for key in "${!ATTS[@]}"; do   value=${ATTS[$key]};  /usr/bin/wget -q -O $SAVEPATH/$value-$CURDATE$EXT https://[...]/$value$EXT;  cp $SAVEPATH/$value-$CURDATE$EXT $SAVEPATH/$value$EXT;done)for key in "${!ATTS[@]}"; do   # due to formatting of the base64 output in the command loop  # the file must be base64 encoded in a variable.  # here we encode the file, in the loop we get in it a var.  value=${ATTS[$key]};  /usr/bin/base64 "$SAVEPATH/$value$EXT" > $SAVEPATH/$value$EXT.base64;done/usr/sbin/sendmail -t <<EOTTO: user@example.orgFROM: automation@example.comBCC: manager@example.orgSUBJECT: State of the union $(date +%c) MIME-Version: 1.0Content-Type: multipart/related;boundary="XYZ"--XYZContent-Type: text/html; charset=ISO-8859-15Content-Transfer-Encoding: 7bit<html><head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-15"></head><body bgcolor="#ffffff" text="#000000">$(for key in "${!ATTS[@]}"; do   value=${ATTS[$key]};  echo "<h1>$key</h1>";  echo "<img src=\"cid:$value\"></br>";done)<a href="https://[...]">More information</a></body></html>$(for key in "${!ATTS[@]}"; do   value=${ATTS[$key]};  ATT=$(cat $SAVEPATH/$value$EXT.base64);  echo "--XYZ"  echo "Content-Type: image/png;name=\"$value$EXT\""  echo "Content-Transfer-Encoding: base64"  echo "Content-ID: <$value>"  echo "Content-Disposition: inline; filename=\"$value$EXT\""  echo ""  echo "$ATT"done)--XYZ--EOTfor key in "${!ATTS[@]}"; do   value=${ATTS[$key]};  rm $SAVEPATH/$value$EXT.base64;done

The --XYZ variable has been copied from a script online.

More images can be added in this loop by editing the array ATTS. Make surethey all have the same extension.

Tags: attachments, automation, bash, inline, mail, outlook, postfix, sendmail, shell, snippets, uuencode