E-Mails mit Lua via SSMTP versenden
SSMTP
Das Programm SSMTP ist ein sehr einfacher
Mail-Transport Agent, der bei Bedarf die zu versendene E-Mail an einen entsprechenden Server weiterleitet.
Es leitet die — auf vielen Unix-Systemen verwendeten — Befehle zum E-Mail-Versand sendmail
sowie mail
auf sich um.
Das Programm läuft jedoch nicht als Server und bricht bei Fehlern schlicht mit einer Fehlermeldung den Versand ab.
SSMTP ist auf vielen Linux-Distributionen über Pakete verfügbar und somit leicht installierbar.
Seine Konfiguration hängt von dem verwendeten Provider und dessen E-Mail-Einstellungen ab.
Für einen einfachen Provider kann die folgende Konfiguration der Datei /etc/ssmtp.conf
(oder — in Abhängigkeit der verwendeten Distribution — aber auch
/etc/ssmtp/ssmtp.conf
) möglicherweise als Beispiel dienen.
root=postmaster
mailhub=smtp.provider.net:465
hostname=mein.server.com
FromLineOverride=YES
UseTLS=YES
AuthUser=username
AuthPass=passwort
Auf der Shell kann die Konfiguration durch den Befehl
printf "SUBJECT: Betreff-Zeile\nFROM: <von@mir.de>\nTO: zu@dir.de\n\nHallo\nBody" | ssmtp zu@dir.de
getestet werden.
Man beachte, dass der Empfänger zu@dir.de
hier doppelt angegeben wird:
Die erste Angabe dient dabei lediglich der Anzeige in der E-Mail, die dem Empfänger (zweite Angabe) angezeigt wird.
Lua
Die Skript-Sprache Lua hat sich als sehr effizient und performant erwiesen, so dass es gerne im VoIP- sowie im Game-Umfeld eingesetzt wird. Aber auch im Web-Bereich findet es mit bspw. HASERL oder in LuCi Verwendung.
Das einfache Versenden einer reinen Text-E-Mail ist über den Umweg eines Shell-Befehles möglich.
local sendto = "zu@dir.de"
local sendfrom = "von@mir.de"
local subject = "Betreff-Zeile"
local body ="Text der E-Mail\nmit dem Zeichen \\\"\\\\\\n\\\" werden die Zeilen voneinander getrennt."
local header ="Subject: "..subject .."\nFrom: "..sendfrom.."\nTo: "..sendto .."\n"
os.execute("echo -e \""..header .."\n"..body.."\" |ssmtp ".. sendto)
Sollen jedoch auch Dateien der E-Mail beigefügt werden, so sollte der Inhalt der E-Mail richtig als mehrteilig formatiert werden. Da Dateien im Allgemeinen oft nicht nur ASCII-Zeichen beinhalten, sind diese vor dem Versand mit Base64 zu encodieren sowie auf die MIME Zeilenlänge von 74 Zeichen zu begrenzen.
-- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss
-- licensed under the terms of the LGPL2
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
function base64(data)
return ((data:gsub('.', function(x)
local r,b='',x:byte()
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
return r;
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
if (#x < 6) then return '' end
local c=0
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
return b:sub(c+1,c+1)
end)..({ '', '==', '=' })[#data%3+1]):gsub("(%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g)","%1\r\n")
end
Damit kann der Versand einer TIFF-Datei und einer PDF-Datei mit Lua wie folgt geschehen.
local sendto = "zu@dir.de"
local sendfrom = "von@mir.de"
local subject = "Betreff-Zeile"
local body ="Text der E-Mail\nmit dem Zeichen \\\"\\\\\\n\\\" werden die Zeilen voneinander getrennt."
local files = {"/pfad/zur/Datei.tif","/pfad/zur/Datei.pdf"}
local header ="Subject: "..subject .."\nFrom: "..sendfrom.."\nTo: "..sendto .."\n"
local contentType = {["tif"]="image/tiff",["pdf"]="application/pdf",["wav"]="audio/wav"}
local boundary = "--------voiscout-boundary-------"
local mailbody = "MIME-Version: 1.0\n"..
"Content-Type: multipart/mixed; boundary="..boundary.."\n\n"..
"This is a multi-part message in MIME format.\n--"..boundary.."\n" ..
"Content-Type: text/plain; charset=utf-8\n"..
"Content-Transfer-Encoding: quoted-printable\n\n"..body.."\n--"..boundary
for i,file in ipairs(files) do
local filename = file:match("[^/]*$")
local f = io.open(file, "r")
if f then
local filecontent = f:read("*all")
f:close()
if filecontent then
mailbody = mailbody .."\n"..
"Content-Type: "..contentType[filename:match("[^%.]*$")].."; name=\\\""..filename.."\\\"\n"..
"Content-Transfer-Encoding: base64\n"..
"Content-Disposition: attachment; filename=\\\""..filename.."\\\"\n\n"
..base64(filecontent).."\n--"..boundary
end
end
end
os.execute("echo -e \""..header..mailbody.."--\" |ssmtp "..sendto)
Sollte durch die Größe der Datei das Limit für Lua zum Absetzen eines Befehls auf die Shell überschritten werden, sollten entsprechende Teile der E-Mail zunächst in eine temporäre Datei geschrieben und diese der E-Mail angefügt werden.
os.execute("(echo -e \""..header..mailbody.."\" && cat "..tmpfile..") |ssmtp "..sendto)
Bei dem Empfang von UTF-8 codierten E-Mails kommt es regelmäßig zu fehlerhaften Darstellungen. Diese können dadurch vermieden werden, dass der Text Quoted-Printable-kodiert wird. Dieses kann beispielsweise durch die folgende Funktion erfolgen.
function qp(txt)
return
txt:gsub("([\000-\031\127-\255=])",function(c) return string.format("=%02X", c:byte()) end)
:gsub(string.rep(".",72), function(x)
return x:find("=",-2) and (x:sub(1,-3) .. x:sub(-2):gsub("=","=\n=")) or x.."=\n"
end)
end
Soll die E-Mail einen HTML-Teil enthalten, so ist der text/plain Teil typischerweise in einem
Content-Type: multipart/alternative; boundary="...."
Block mit einer eigenen Boundary eingebettet. Der letzte dieser alternativen Teile wird jeweils versucht anzuzeigen,
so dass der HTML-Teil normalerweise der reinen Text-Alternative folgt und somit der letzte ist.
Beim Verfassen des HTML-Teils ist jedoch besondere Vorsicht geboten, da die unterschiedlichen E-Mail-Programme jeweils unterschiedliche Teile
des HTML-Standards nur darstellen.