2020-12-08

Python: send emails with embedded images

to send emails with images you need to use MIMEMultipart, but the basic approach:

import smtplib

from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage

msg = MIMEMultipart('alternative')
msg['Subject'] = "subject"
msg['From'] = from_addr
msg['To'] = to_addr

part = MIMEImage(open('/path/to/image', 'rb').read())

s = smtplib.SMTP('localhost')
s.sendmail(from_addr, to_addr, msg.as_string())
s.quit()

will produce an email with empty body and the image as an attachment.

The better way, ie to have the image as part of the body of the email, requires to write an HTML body that refers to that image:

import smtplib

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage

msg = MIMEMultipart('alternative')
msg['Subject'] = "subject
msg['From'] = from_addr
msg['To'] = to_addr

text = MIMEText('<img src="cid:image1">', 'html')
msg.attach(text)

image = MIMEImage(open('/path/to/image', 'rb').read())

# Define the image's ID as referenced in the HTML body above
image.add_header('Content-ID', '<image1>')
msg.attach(image)

s = smtplib.SMTP('localhost')
s.sendmail(from_addr, to_addr, msg.as_string())
s.quit()

The trick is to define an image with a specific Content-ID and make that the only item in an HTML body: now you have an email with contains that specific image as the only content of the body, embedded in it.

Bonus point: if you want to take a snapshot of a webpage (which is kinda the reason i needed the code above) i found it extremely useful to use the Google PageSpeed Insights API; a good description on how to use that API with Python is available at this StackOverflow answer.

UPDATE (2020-12-26): I was made aware via email that some mail providers may not display images inline when the Content-ID value is too short (say, for example, Content-ID: 1). A solution that seems to work on most of the providers is using a sequence of random chars prefixed with a dot and suffixed with a valid mail domain.

2020-11-05

QNAP firmware 4.5.1.1465: disable ssh management menu

as a good boy i just upgraded my QNAP NAS to the latest available firmware, 4.5.1.1465, but after the reboot there's an ugly surprise awaiting for me

once i ssh'd into the box to do my stuff, instead of a familiar bash prompt i'm greeted by a management menu that allows me to perform some basic management tasks or quit it and go back to the shell. i dont really need this menu (in particular because i have automations that regularly ssh into the box and they are not meant to be interactive).

to disable it: edit /etc/profile and comment the line "[[ "admin" = "$USER" ]] && /sbin/qts-console-mgmt -f" (you can judge me later for sshing as root)

UPDATE (2020-12-26): as pointed out in the comments, and discovered now after an upgrade, the menu comes back up after because /etc/profile is a system file for QNAP so gets replaced/updated by them often

2020-10-23

Multiple git configurations depending on the repository path

For my work on Debian, i want to use my debian.org email address, while for my personal projects i want to use my gmail.com address.

One way to change the user.email git config value is to git config --local in every repo, but that's tedious, error-prone and doesn't scale very well with many repositories (and the chances to forget to set the right one on a new repo are ~100%).

The solution is to use the git-config ability to include extra configuration files, based on the repo path, by using includeIf:

Content of ~/.gitconfig:

[user]
    name = Sandro Tosi
    email = <personal.address>@gmail.com

[includeIf "gitdir:~/deb/"]
    path = ~/.gitconfig-deb

Every time the git path is in ~/deb/ (which is where i have all Debian repos) the file ~/.gitconfig-deb will be included; its content:

[user]
    email = morph@debian.org

That results in my personal address being used on all repos not part of Debian, where i use my Debian email address. This approach can be extended to every other git configuration values.

2020-06-11

Installing prometheus snmp_exporter on a QNAP nas

I've this project in the background about creating a grafana dashboard for a QNAP nas.

As the summer is ramping up, i wanted to figure out the temperature of the nas throughout the day, so.. prometheus + grafana to the rescue!

I wrote the instructions to install snmp_exporter on a linux-based QNAP nas. For now i'm using an already existing dashboard, but it's the first step to create my own.

2020-05-08

It's a waiting game... but just how long we gotta wait?

While waiting for my priority date to become current, and with enough "quarantine time" on my hand, i just come up with a very simple Python tool to parse the USCIS Visa Bulletin to gather some data from that.

You can find code and images in this GitHub repo.

For now it only contains a single plot for the EB3 final action date; it answers a simple question: how many months ago your priority date should be if you want to file your AOS on that month. We started from FY2016, to cover the final full year of the Obama administration.

If you're interested in more classes/visas, let me know and the tool could be easily extended to cover that too. PRs are always welcome.

2016-12-11

What's that code: Elementary S04E09

they hacked a car and around 7:27 in the episode they are analyzing the car's computer source code, that's some sweet compression they say, but it turns out it's Perl interpreter source code, with Perl replaced with Auto (after all it's the auto code right?)

https://perl5.git.perl.org/perl.git/blob/HEAD:/perl.c#l431 and following lines

another interesting code copy was in The Americans (cant remember season or episode), when they were trying to acquire the ECHO program source code, what's on the screen is actually MATLAB source code

2016-11-02

Debian source package name from the binary name

it looks like i forgot all the times how to do that, and apparently i'm not able to use google good enough to find it out quickly, let's write down one way to get the source package name from the binary package name:

dpkg-query -W -f='${source:package}\n' <list of bin pkgs>

(since it accepts a list of packages, you can xargs it).

there are probably another million ways to do that, so dont be shy and comment this post if you want to share your method