E-Mail senden: Unterschied zwischen den Versionen

Aus FHEMWiki
K (Wikifiziert + kleinere Korrekturen + zusätzlichen Kategorien zugeordnet)
K (Snippet für cUrl mit Feedback aus Forum verbessert für Nachrichten mit Zeilenumbrüchen)
 
(63 dazwischenliegende Versionen von 19 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
Um aus FHEM heraus '''E-Mail senden''' zu können, sind abhängig von der verwendeten Platform unterschiedliche Vorgehensweisen erforderlich.
Um aus FHEM heraus E-Mails senden zu können, gibt es unterschiedliche Methoden, abhängig von der verwendeten Plattform.


== Linux ==
Lange Zeit war <code>sendemail</code> sehr beliebt. Da aber die Homepage des Projekts nicht mehr online ist und Probleme nur noch via erhöhtem Supportaufwand gelöst werden, sollte diese Option als veraltet betrachtet werden.
=== FritzBox 7170 (non-chroot) ===
Datei 99_email.pm im Modul-Verzeichnis mit folgender Funktion anlegen (oder in bestehende 99_irgendwas.pm kopieren):


<nowiki>sub fb_mail {
Eine Liste mit ressourcensparenden E-Mails Clients findet man bei dem OpenWRT Projekt: https://openwrt.org/docs/guide-user/services/email/smtp.client
my $rcpt = $_[0];
my $subject = $_[1];
my $text = $_[2];
system(&quot;/bin/echo \&quot;$text\&quot; | /usr/bin/mail send -i - -s \&quot;$subject\&quot; -t \&quot;$rcpt\&quot;&quot;);
}</nowiki>
Aufruf dann mittels
:<code>{ fb_mail('empfaenger@@mail.de','Subject','text 123') }</code>


=== Fritz!Box 7390 ===
MSGMail ist ein FHEM eigenes Modul zum Versenden, die Einrichtung ist allerdings nicht gänzlich einfach. Anfängern sei die cURL Methode empfohlen.
Auf der [[AVM Fritz!Box|FritzBox 7390]] ist diese Funktion seit 10/2012 Bestandteil der Fhem Standardauslieferung. Sie ist untergebracht in FritzBoxUtils.pm und heisst dort FB_mail($$$) (Groß-Kleinschreibung beachten).


Da der Dateiname von FritzBoxUtils.pm nicht mit 99_ beginnt, wird diese Programmdatei nicht automatisch beim Start von Fhem geladen. Fhem muss zum Laden dieser Programmdatei aufgefordert werden. Dazu (z.&nbsp;B. in 99_myUtils.pm) die Zeile ''use FritzBoxUtils;'' einfügen.
=== MSGMail (Linux, Windows) ===
FHEM bringt ein eigenes Device zum Senden von E-Mails mit, welches in Perl implementiert ist: [https://fhem.de/commandref.html#MSGMail MSGMail, https://fhem.de/commandref.html#MSGMail]


Mit dem Install von AVM.de wird fhem in einer chroot-Umgebung ausgeführt, die den Zugriff auf die Mailfunktion der Fritzbox nicht zulässt. Daher muss Fhem in der [http://fhem.de/fhem.html#Download Version von fhem.de] installiert sein. Sollte Ihre Fritzbox bisher mit dem install von AVM laufen, kann (nach einem backup!) das image von fhem.de einfach drüberinstalliert werden. Es sollten dabei alle Einstellungen erhalten bleiben.
=== cURL (Linux, Windows) ===
[https://curl.se/ cURL] kann auf praktisch [https://curl.se/download.html jedem Betriebssystem] genutzt werden, [https://curl.se/windows/ selbst unter Windows]. Es kann direkt mit einem SMTP Server E-Mails versenden und stellt damit eine moderne, portable und sichere Option zum Versenden von E-Mails dar.


<nowiki>sub fb_mail {
In FHEM richtet man sich ein Device ein und passt die Details (<code>$emailTo, $emailFrom, $emailServer</code>) an. Das Programm cURL muss installiert sein (z.B. mit <code>apt install curl</code>, oder durch Herunterladen und Installieren von der [https://curl.se cURL-Webseite]).<syntaxhighlight lang="perl" line="1">
my $rcpt = $_[0];
defmod sendMail dummy
my $subject = $_[1];
attr sendMail readingList message password
my $text = $_[2];
attr sendMail setList message:textField-long password
system(&quot;/bin/echo \&quot;$text\&quot; &gt; /var/tmp/fhem_nachricht.txt&quot;);
attr sendMail userReadings state:message:[\s\S]* {\
system(&quot;/sbin/mailer send -i '/var/tmp/fhem_nachricht.txt' -s \&quot;$subject\&quot; -t \&quot;$rcpt\&quot;&quot;);
my $emailTo  = 'you@example.com';;\
system(&quot;rm /var/tmp/fhem_nachricht.txt&quot;);
my $emailFrom = 'fhem@example.org';;\
}</nowiki>
my $emailServer = 'mail.smtpserver.de';;\
\
# Passwort aus getKeyValue abrufen\
my ($err, $emailPass) = getKeyValue("${name}_password");;\
if ($err || !defined $emailPass) {\
return "Error retrieving password: $err";;\
}\
\
my $message = ReadingsVal($name, 'message', '???');;\
my $subject = "$name: FHEM Nachricht";;\
\
# Betreff extrahieren und aus der Nachricht entfernen\
if ($message =~ s/(?:Subject|Betreff)=["'](.*?)["']//) {\
$subject = $1;;\
}\
\
# Empfänger extrahieren und aus der Nachricht entfernen\
if ($message =~ s/(?:To|An)=["'](.*?)["']//) {\
$emailTo = $1;;\
}\
\
#Dateianhänge bestimmen\
my @attachments;;\
while ($message =~ s/(?:Attachment|Anhang)=["'](.*?)["']//) {\
my $file = $1;;\
return ">>$file<< not found, not sending email" unless (-e $file);;\
push (@attachments, $file);;\
}\
\
#der curl Befehl wird hier aufgebaut:\
my $cmd = "curl -m 19 --noproxy '*' --no-progress-meter --ssl-reqd smtps://$emailServer:465 ";;\
$cmd .= "--user '$emailFrom:$emailPass' --mail-from '$emailFrom' --mail-rcpt '$emailTo' ";;\
$cmd .= "--write-out 'Email sent with status %{http_code}\n' ";;\
$cmd .= "-H 'Subject: $subject' ";;\
$cmd .= "-H 'From: $emailFrom' ";;\
\
#multipart/alternative für Text und HTML EMail Body\
$cmd .= "-F '=(;;type=multipart/alternative' ";;\
\
# Leerzeichen und <br> bzw <br \> am Anfang entfernen:\
$message =~ s/^(\s|<br(?:[ \/]+)>)+//;;\
# Leerzeichen und <br> bzw <br \> am Ende entfernen:\
$message =~ s/(\s|<br(?:[ \/]+)>)+$//;;\
\
#Plaintext E-Mail Inhalt an cURL:\
$cmd .= "-F \"=$message;;type=text/plain;; charset=UTF-8\" ";;\
#ersetze \n bzw. \r\n durch ein HTML-tag <br />:\
$message =~ s/\r?\n/<br \/>/g;;\
\
#HTML E-Mail Inhalt an cURL:\
$cmd .= "-F '= <body>$message</body>;;type=text/html;; charset=UTF-8' ";;\
$cmd .= "-F '=)' ";;\
\
#jetzt alle Attachments (0..N) anhängen:\
foreach my $file (@attachments) {\
$cmd .= "-F '=@".$file.";;encoder=base64' ";;\
}\
\
#stderr auch mit in den output sammeln:\
$cmd .= " 2>&1";;\
\
#Blockierender Aufruf von cURL in dieser Funktion via BlockingCall:\
if (!defined &sendMailfunc1) {\
*sendMailfunc1 = sub ($) {\
my ($param) = @_;;\
my $result;;\
$result = qx/$param/;;\
$result = MIME::Base64::encode_base64($result);;\
$result =~ s/\n//g;;\
return $result;;\
}\
}\
\
#Rückgabe über diese Funktion,\
#anzeigen in dem reading dieses UserReadings:\
if (!defined &sendMailfunc2) {\
*sendMailfunc2 = sub ($) {\
my ($result) = @_;;\
my $hash = $defs{$name};;\
$result = MIME::Base64::decode_base64($result);;\
readingsSingleUpdate($hash, $reading, $result, 1);;\
}\
}\
\
#funktion falls BlockingCall abgebrochen wird:\
if (!defined &sendMailfunc3) {\
*sendMailfunc3 = sub ($) {\
my ($result) = @_;;\
my $hash = $defs{$name};;\
readingsSingleUpdate($hash, $reading, $result, 1);;\
}\
}\
\
BlockingCall("sendMailfunc1", $cmd, "sendMailfunc2", 20, "sendMailfunc3", "Error: timeout");;\
\
return "started cURL command...";;\
},\
state:password:.* {\
# Passwort speichern\
my $ret = setKeyValue("${name}_password", ReadingsVal($name, 'password', undef)) // "password stored";;\
\
#password wieder aus der Variablen rausnehmen, soll nicht sichtbar bleiben:\
#\
# Hinweis: das Password taucht beim Setzen hierüber im Event-Log auf!\
# Alternativ: { setKeyValue("sendMail_password", "geheimesPasswort") }\
readingsBulkUpdate($hash, "password", "****");;\
\
return "$ret";;\
}
</syntaxhighlight>Das Passwort setzt man mit:


Aufruf dann mittels
* <code>set sendMail password geheimesPasswort</code>
:<code>{ fb_mail('empfaenger@mail.de','Subject','text 123') }</code>
* Alternativ, damit das Passwort nicht im Log auftaucht: <code>{ setKeyValue("sendMail_password", "geheimesPasswort") }</code>
bzw.
:<code>{ FB_mail('empfaenger@mail.de','Subject','text 123') }</code>


'''Hinweis:''' Wenn der Aufruf der Mailfunktion aus einem notify oder at erfolgt, muss das @@ in der Adresse des Mailempfängers verdoppelt werden, da ein einfaches @ sonst durch den Namen des getriggerten Devices  ersetzt würde. Bei Verwendung in der fhem-Kommandozeile oder einem eigenen *Utils.pm ist diese Doppelung nicht erforderlich. Bitte bei den ersten Mails ins Log schauen, ob die Mailadresse wie gewünscht verwendet wird.
E-Mails kann man dann Senden mit:


Dem Mailer können noch weitere Parameter hinzugefügt werden. Mehr dazu siehe: [http://www.wehavemorefun.de/fritzbox/Mailer Mailer]
* <code>set sendMail message Mein Text</code> (es wird der Standardbetreff und Empfänger aus dem Snippet genutzt)
* <code>set sendMail message Betreff="Mein Betreff" Mein Text</code>(es wird der Empfänger aus dem Snippet genutzt)
* <code>set sendMail message Subject="Dies ist ein Test" Mein Text</code>
* <code>set sendMail message To="jemand@example.com" Mein Text</code>
* <code>set sendMail message An="jemand@example.com" Mein Text</code>
* <code>set sendMail message An="jemand@example.com" Betreff="Mein Betreff" Mein Text</code>
* <code>set sendMail message To="jemand@example.com" Subject="Mein Betreff" Mein Text</code>
* <code>set sendMail message Subject="✅ Dies ist ein Test" Meldung mit Emoji ⚽ geht auch</code>
* Eine Datei mit anhängen: <code>set sendMail message Subject="Dies ist ein Test" Anhang="www/images/fhemSVG/bag.svg" Mein Text</code>
* Zwei Dateien mit anhängen: <code>set sendMail message Subject="Dies ist ein Test" Anhang="./www/images/fhemSVG/bag.svg" Anhang="www/images/fhemSVG/batterie.svg" Mein Text</code>, für die anzuhängenden Dateien können relative und absolute Pfade verwendet werden. Beim Vorbereiten der E-Mail wird geprüft ob die Dateien existieren, da dies sonst eine typische Fehlerquelle ist. Es wird nichts versendet wenn eine Datei nicht gefunden werden kann.


=== Synology DiskStation ===
==== Fehlersuche ====
Beim DSM 3.2 gab es keinen <code>sendmail</code>-Befehl, sondern nur eine Funktion für den Versand der System-Benachrichtigungen. Interessanterweise funktionierte aber der <code>php-mail</code>-Befehl, so dass man mittels folgendem Modul Mails frei versenden kann:
Sollte cURL zwar installiert sein, aber keine E-Mails versenden, kann es sein, dass das Protokoll nicht einkompiliert wurde. Dies ist bei OpenWRT zum Beispiel der Fall.


<nowiki>sub sendmail($$$) {
So sollte es aussehen (hier ein Ubuntu), relevant ist für diese Nutzung das Protokoll smtp und smtps, das braucht man:<syntaxhighlight lang="bash">
my($empf, $subj, $nachricht) = @_;
curl -V
system(&quot;php -r 'mail(\&quot;$empf\&quot;,\&quot;$subj\&quot;,\&quot;$nachricht\&quot;);'&quot;);
curl 8.5.0 (x86_64-pc-linux-gnu) libcurl/8.5.0 OpenSSL/3.0.13 zlib/1.3 brotli/1.1.0 zstd/1.5.5 libidn2/2.3.7 libpsl/0.21.2 (+libidn2/2.3.7) libssh/0.10.6/openssl/zlib nghttp2/1.59.0 librtmp/2.3 OpenLDAP/2.6.7
  undef;
Release-Date: 2023-12-06, security patched: 8.5.0-2ubuntu10.6
}</nowiki>
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM PSL SPNEGO SSL threadsafe TLS-SRP UnixSockets zstd
 
</syntaxhighlight>So sollte es nicht aussehen (hier ein OpenWRT):<syntaxhighlight lang="bash">
curl: (1) Protocol "smtps" not supported
 
curl -V
curl 8.10.1 (arm-openwrt-linux-gnu) libcurl/8.10.1 mbedTLS/3.6.2 nghttp2/1.63.0
Release-Date: 2024-09-18
Protocols: file ftp ftps http https ipfs ipns mqtt
Features: alt-svc HSTS HTTP2 HTTPS-proxy IPv6 Largefile SSL threadsafe UnixSockets
 
</syntaxhighlight>Hat man nur ein cURL ohne das Protokoll, so muss man sich das Paket leider anderweitig beschaffen (chroot, selbst kompilieren, statisch gelinkte Version, ...).
 
==== Forumlink ====
https://forum.fhem.de/index.php?topic=140814.0
 
=== EXIM4 (Debian) ===
Eine Anleitung zum Versenden von E-Mails mit Exim ist als PDF verfügbar: [[Medium:Anleitung Exim4 Debian GMX.pdf|PDF]]
 
=== SSMTP (OpenWRT, embedded Distros) ===
 
==== Installation ====
<syntaxhighlight lang="bash">
opkg update
opkg install ssmtp_2.64-4_mpc85xx.ipk  
</syntaxhighlight>Damit <code>ssmtp</code> funktioniert müssen die Dateien <code>/etc/ssmtp/ssmtp.conf</code> und <code>/etc/ssmtp/revaliases</code> angepasst werden.


=== Raspberry Pi ===
/etc/ssmtp/ssmtp.conf
In der weezy-Version, wie sie von busware zur Verfügung gestellt wird, muss auf einem [[Raspberry Pi]] noch sendEmail nachinstalliert werden:
<syntaxhighlight lang="text">
root=arnold@gmx.net
mailhub=mail.gmx.net:465
rewriteDomain=gmx.net
hostname=gmx.net
FromLineOverride=YES
UseTLS=YES
#UseSTARTTLS=YES
AuthUser=arnold@gmx.net
AuthPass=Passwort_von_arnold@gmx.net
</syntaxhighlight>


<pre>
/etc/ssmtp/revaliases
sudo apt-get update
<syntaxhighlight lang="text">
sudo apt-get install sendEmail
root:arnold@gmx.net:mail.gmx.net:465
</pre>
</syntaxhighlight>


in der [[99_myUtils_anlegen|99_myUtils]] folgende Unterroutine einfügen:
In der [[99_myUtils_anlegen|99_myUtils]] folgende Unterroutine einfügen:


<nowiki>######## DebianMail  Mail auf dem RPi versenden ############
<syntaxhighlight lang="perl">
sub  
sub OpenWRTMail
DebianMail
{  
{  
  my $rcpt = shift;
  my $rcpt = shift;
  my $subject = shift;  
  my $subject = shift;  
  my $text = shift;  
  my $text = shift;  
  my $ret = &quot;&quot;;
  my $ret = "";
  my $sender = &quot;absender\@account.de&quot;;
  my $sender = "dockstar\@heye-tammo.de";  
my $konto = &quot;kontoname\@account.de&quot;;
  Log 1, "sendEmail RCP: $rcpt, Subject: $subject, Text: $text";
my $passwrd = &quot;passwrd&quot;;
  $ret .= qx(echo -e 'to:$rcpt\n from:$sender\nsubject:$subject\n$text\n' | ssmtp $rcpt);
my $provider = &quot;smtp.provider.de&quot;;
  Log 1, &quot;sendEmail RCP: $rcpt&quot;;
Log 1, &quot;sendEmail Subject: $subject&quot;;
Log 1, &quot;sendEmail Text: $text&quot;;
  $ret .= qx(sendEmail -f '$sender' -t '$rcpt' -u '$subject' -m '$text' -s '$provider' -xu '$konto' -xp '$passwrd' -o tls=no);
  $ret =~ s,[\r\n]*,,g;    # remove CR from return-string  
  $ret =~ s,[\r\n]*,,g;    # remove CR from return-string  
  Log 1, &quot;sendEmail returned: $ret&quot;;  
  Log 1, "sendEmail returned: $ret";  
}</nowiki>
}
</syntaxhighlight>


Beim Aufruf der Funktion gibt es zwei unterschiedliche Verhaltensweisen zu beachten. Wird DebianMail durch ein Fhem-Ereignis als Makro mit "Transferzeichen", wie @ oder&#160;% aufgerufen, so sind diese innerhalb des Aufrufs von DebianMail zu maskieren.
=== PHP Mail Funktion (Synology DiskStation) ===
Beim DSM 3.2 funktioniert der <code>php-mail</code>-Befehl, so dass man mittels folgendem Modul E-Mails versenden kann:
<syntaxhighlight lang="perl">
sub sendmail($$$) {
my($empf, $subj, $nachricht) = @_;
system("php -r 'mail(\"$empf\",\"$subj\",\"$nachricht\");'");
}
</syntaxhighlight>


Siehe auch commandref:
=== Sendemail (Veraltet, Debian-basierende Distros) ===
* The character @ will be replaced with the device name. To use @ in the text itself, use the double mode (@@).
Es handelt sich um ein Perl Programm, dass man aus den Paketquellen installieren kann.
* The macro&#160;%&lt;parameter&gt; will expand to the current value of the named parameter. This can be either a parameter from the device definition or a parameter from the set or get command.


Beispiel:
Es gibt Probleme:


<nowiki>define Sonstiges notify Fenster:Window:.*,.*Low.Batt*. {\
* mit der TLS bzw STARTTLS Verschlüsselung (https://github.com/fhem/fhem-docker/issues/254, https://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg1915977.html) ,
DebianMail('email@@email.domain','Subject','Text');;\
* Mit der Webseite des Projekts (https://web.archive.org/web/20190906140125/http://caspian.dotconf.net/menu/Software/SendEmail); diese ist nicht mehr verfügbar und nur eine archivierte Kopie kann eingesehen werden,
}</nowiki>


in allen anderen Fällen muss die Maskierung entfallen:
weswegen diese Lösung als technisch überholt gelten sollte. Will man trotzdem <code>sendemail</code> verwenden folgenden hier die Informationen dazu:


Beispiel:
Auf dem Server muss <code>sendemail</code> installiert werden:<syntaxhighlight lang="bash" line="1">
sudo apt-get update
sudo apt-get install sendemail libio-socket-ssl-perl libnet-ssleay-perl perl
</syntaxhighlight>Man kann die korrekte Funktion im Terminal (ohne <code>{qx()}</code> ) oder auch in der FHEM Kommandozeile testen (Hinweis: manche Provider (z.B. gmail) lassen diesen Zugang erst nach Freischaltung zu!).
''Bei Gmail muss seit dem 30.6.2022 ein separates Passwort erzeugt werden, die alte Einstellung über "Zugriff durch weniger sichere Apps" funktioniert nicht mehr. Siehe Support Seite Google: <nowiki>https://support.google.com/accounts/answer/185833</nowiki>''
 
''Beispiel mit Gmail über Linux Terminalfenster:''
sendemail -f 'Der.Absender@gmail.com' -t 'Der.Empfaenger@gmail.com' -u 'subject' -m 'text' -a <nowiki>''</nowiki> -s 'smtp.gmail.com:587' -xu 'Der.Absender' -xp DASSUPERGEHEIMEPASSW0RT
In der [[99 myUtils anlegen|99_myUtils]] folgende Unterroutine einfügen:<syntaxhighlight lang="perl" line="1">
######## DebianMail  Mail auf dem RPi versenden ############
# $provider für SMTP Server anpassen.
# Einmal in der FHEM Kommandozeile, user und password anpassen:
# {setKeyValue("myEmailKonto",'user@domain');;setKeyValue("myEmailPasswrd",'password')}
sub DebianMail
{
my $rcpt = shift;
my $subject = shift;
my $text = shift;
my $attach = shift;
my $ret = "";
my $error;
my $konto = getKeyValue("myEmailKonto");
my $passwrd = getKeyValue("myEmailPasswrd");
my $from = $konto; # or use different KeyValue if konto is not the from email address
my $provider = "smtp.1und1.de"; # smtp.domain.tld:port see provider documentation
#Log 1, "sendEmail RCP: $rcpt";
#Log 1, "sendEmail Subject: $subject";
#Log 1, "sendEmail Text: $text";
#Log 1, "sendEmail Anhang: $attach";
if (not defined($attach)){$attach=''}
$ret .= qx(sendemail -f '$from' -t '$rcpt' -u '$subject' -m '$text' -a $attach -s '$provider' -xu '$konto' -xp '$passwrd' -o tls=auto -o message-charset=utf-8);
$ret =~ s,[\r\n]*,,g;    # remove CR from return-string
Log 1, "sendemail returned: $ret";
}
###############################################################################
</syntaxhighlight>
Die Zugangsdaten für den Email-Account müssen dabei FHEM-intern gespeichert werden. Dazu gibt man einmalig über die Kommandozeile folgendes ein (user@domain und password müssen auf den Email Account geändert werden):


  <nowiki>define Sonstiges at *01:00:00 {\
: <code>{setKeyValue("myEmailKonto",'user@domain');;setKeyValue("myEmailPasswrd",'password')}</code>
DebianMail('email@email.domain','Subject','Text');;\
}</nowiki>


=== BeagleBoard-xM ===
Um die TLS Verschlüsselung (ehem. SSL) nicht zu nutzen, muss in der viertletzten Zeile tls=no verwendet und der Port des Mailproviders auf 25 eigetragen werden. Sollte anschließend keine Mail verschickt werden, siehe Probleme.
Auf einem [[:Kategorie:BeagleBoard-xM|BeagleBoard-xM]] mit einem [http://en.opensuse.org/HCL:BeagleBoard-xM OpenSUSE 12.2] kann man ebenfalls das Perl-Programm ''sendEmail'' wie beim RPi nutzen. Dies gibt es aber nicht in den Repositories von openSUSE, sondern man muss sich ''sendEmail'' als Source herunterladen. Das geht am einfachsten per ''wget'', welches man ebenfalls erst installieren muss (aber aus einem Repository).


<nowiki>$ zypper in wget
Falls der Body-Text in einem (Android-)Mailer auf dem Handy nicht gezeigt wird, kann der Parameter '''-o message-content-type=html''' helfen.
$ cd /opt
$ wget http://caspian.dotconf.net/menu/Software/SendEmail/sendEmail-v1.56.tar.gz
$ tar xvfz sendEmail-v1.56.tar.gz
$ cd sendEmail-v1.56
$ cp sendMail /usr/local/bin</nowiki>
Dann geht man weiter vor wie unter RPi beschrieben (anlegen der SUB-Routine in 99_myUtils usw.).


'''Hinweis:''' Die Version 1.56 von ''sendEmail'' ist Stand Januar 2013 die aktuelle. Da diese Programmversion von 2009 stammt, ist mit neuen Versionen selten zu rechnen. Vielleicht schauen Sie trotzdem vorher auf der [http://caspian.dotconf.net/menu/Software/SendEmail/ Homepage von sendEmail] nach.
Die Funktion kann beispielsweise folgendermaßen aufgerufen werden:<syntaxhighlight lang="perl">
{qx(sendemail -f 'Ab\@send.er' -t 'Emp\@faeng.er' -u 'subject' -m 'text' -a 'DateinameOderLeer' -s 'smtpFQDN:port' -xu 'MailUser' -xp 'PasswortOhneKlammeraffen')}
</syntaxhighlight>Bei allen Feldern können generell doppelte " oder einfache ' Anführungszeichen verwendet werden. Innerhalb von "" müssen Sonderzeichen wie @ aber maskiert werden, da sie sonst als Steuerzeichen interpretiert werden:


== Windows ==
: <code>"email\@email.domain" oder 'email@email.domain'</code>
# Kopiere die Datei sendEmail.exe* in Dein FHEM Verzeichnis (hier c:\fhem-5.0\); Quelle: [http://caspian.dotconf.net/menu/Software/SendEmail/ http://caspian.dotconf.net/menu/Software/SendEmail/]
# Erstelle im FHEM Verzeichnis die Datei wmail.bat mit folgendem Inhalt (eine Zeile): <br><code>sendEmail -f absender@domain.de -u "%1" -m " " -s SMTP-SERVERAdresse -xu SMTP_USERNAME -xp SMTP_PASSWORT -t empfänger@domain.de -o message-header="X-Message-Flag: FHEM"</code>
# Beispiel fhem.cfg
## Mail wenn sich der Status von Heizung.* oder Hzg.* ändert <br><code>define Mail_Heizung notify Heizung.*|Hzg.* { system("wmail @:%")}</code>
## Mail bei Signal Aussentemperatur (für dieses Beispiel wird [http://fhem.de/commandref.html#getstate http://fhem.de/commandref.html#getstate getstate] benötigt) <br><code>define Mail_Aussentemperatur notify Aussentemperatur {\</code><br><code>my ($val);;\</code><br><code>$val = fhem "getstate @";;\</code><br><code>system("wmail \"@: $val\"");;\</code><br><code>}</code>


== Probleme ==
Direkt in der FHEM Kommandozeile (ohne Anhang)
=== sendEmail ===
Falls man keine E-Mails verschicken kann, kann man in einem ersten Test prüfen, ob sendEmail als solches funktioniert und die Konfiguration (Benutzer, Passwort, Server-Name usw.) des Mail-Kontos, über das die Mails abgesetzt werden sollen, richtig ist.


Hierzu setzt man in der FHEM-Befehlszeile die folgende Anweisung ab:
: <code>{DebianMail("email\@email.domain","Subject","Text")}</code>
:<code>{ SUB-Routinen-Name('EMailAdresse@Mail.Domain','Test','Test-Text');; }</code>
und ersetzt ''SUB-Routinen-Name'' durch den Namen der in 99_myUtils erzeugten Prozedur. Statt ''EMailAdresse@Mail.Domain'' trägt man noch eine gültige E-Mail-Adresse ein und bestätigt den Befehl dann mittels &lt;Enter&gt; (nicht "save"). Empfangen Sie nicht kurzfristig eine entsprechende E-Mail, ist sehr wahrscheinlich an den Zugangsdaten etwas verkehrt.


Vor dem testen der Routine oben kann sendEmail auch über die Konsole (z.&nbsp;B. via Putty) getestet werden:
Die ordnungsgemäße Ausführung wird mit 71 quittiert.
:<code>sendEmail -f 'fhemsystem@meinedomain.tld' -t 'ich@meinedomain.tld' -u 'subject' -m 'body' -s 'meinmailserver.meinedomain.de' -xu 'fhemmailer' -xp 'geheimespassword' -o tls=no</code>


== Email laut Log gesendet aber nicht angekommen? ==
Beispiele mehrere Anhänge (Es ist wichtig Dateinamen mit Leerzeichen in separate Anführungszeichen zu setzen)
Dann bitte in der Fritzbox Oberfläche überpüfen, ob unter "System" -> "Push Service" selbiger eingerichtet und aktiviert wurde.  
{DebianMail("email\@email.domain","Subject","Text","Anhang1 Anhang2 Anhang3")}
{DebianMail('email@email.domain','Subject','Text',"'with spaces Anhang1' 'with spaces Anhang2'")}
oder (mehr als einen Empfänger, diese können durch Leerzeichen, Semikolon oder Komma getrennt sein)
define Sonstiges at *01:00:00 {\
DebianMail('email@email.domain,email2@email.domain',"Subject","Text","'Anhang1' 'Anhang2' ...");;\
}


[[Kategorie:HOWTOS]]
Die archivierte Doku zu <code>sendemail</code> befindet sich in der Änderungshistorie: https://wiki.fhem.de/w/index.php?title=E-Mail_senden&oldid=37524
[[Kategorie:FritzBox]]
[[Kategorie:E-Mail]]
[[Kategorie:BeagleBoard-xM]]
[[Kategorie:Raspberry Pi]]

Aktuelle Version vom 28. Februar 2025, 08:31 Uhr

Um aus FHEM heraus E-Mails senden zu können, gibt es unterschiedliche Methoden, abhängig von der verwendeten Plattform.

Lange Zeit war sendemail sehr beliebt. Da aber die Homepage des Projekts nicht mehr online ist und Probleme nur noch via erhöhtem Supportaufwand gelöst werden, sollte diese Option als veraltet betrachtet werden.

Eine Liste mit ressourcensparenden E-Mails Clients findet man bei dem OpenWRT Projekt: https://openwrt.org/docs/guide-user/services/email/smtp.client

MSGMail ist ein FHEM eigenes Modul zum Versenden, die Einrichtung ist allerdings nicht gänzlich einfach. Anfängern sei die cURL Methode empfohlen.

MSGMail (Linux, Windows)

FHEM bringt ein eigenes Device zum Senden von E-Mails mit, welches in Perl implementiert ist: MSGMail, https://fhem.de/commandref.html#MSGMail

cURL (Linux, Windows)

cURL kann auf praktisch jedem Betriebssystem genutzt werden, selbst unter Windows. Es kann direkt mit einem SMTP Server E-Mails versenden und stellt damit eine moderne, portable und sichere Option zum Versenden von E-Mails dar.

In FHEM richtet man sich ein Device ein und passt die Details ($emailTo, $emailFrom, $emailServer) an. Das Programm cURL muss installiert sein (z.B. mit apt install curl, oder durch Herunterladen und Installieren von der cURL-Webseite).

defmod sendMail dummy
attr sendMail readingList message password
attr sendMail setList message:textField-long password
attr sendMail userReadings state:message:[\s\S]* {\
	my $emailTo   = 'you@example.com';;\
	my $emailFrom = 'fhem@example.org';;\
	my $emailServer = 'mail.smtpserver.de';;\
	\
	# Passwort aus getKeyValue abrufen\
	my ($err, $emailPass) = getKeyValue("${name}_password");;\
	if ($err || !defined $emailPass) {\
		return "Error retrieving password: $err";;\
	}\
	\
	my $message = ReadingsVal($name, 'message', '???');;\
	my $subject = "$name: FHEM Nachricht";;\
	\
	# Betreff extrahieren und aus der Nachricht entfernen\
	if ($message =~ s/(?:Subject|Betreff)=["'](.*?)["']//) {\
		$subject = $1;;\
	}\
	\
	# Empfänger extrahieren und aus der Nachricht entfernen\
	if ($message =~ s/(?:To|An)=["'](.*?)["']//) {\
		$emailTo = $1;;\
	}\
	\
	#Dateianhänge bestimmen\
	my @attachments;;\
	while ($message =~ s/(?:Attachment|Anhang)=["'](.*?)["']//) {\
		my $file = $1;;\
		return ">>$file<< not found, not sending email" unless (-e $file);;\
		push (@attachments, $file);;\
	}\
	\
	#der curl Befehl wird hier aufgebaut:\
	my $cmd = "curl -m 19 --noproxy '*' --no-progress-meter --ssl-reqd smtps://$emailServer:465 ";;\
	$cmd .= "--user '$emailFrom:$emailPass' --mail-from '$emailFrom' --mail-rcpt '$emailTo' ";;\
	$cmd .= "--write-out 'Email sent with status %{http_code}\n' ";;\
	$cmd .= "-H 'Subject: $subject' ";;\
	$cmd .= "-H 'From: $emailFrom' ";;\
	\
	#multipart/alternative für Text und HTML EMail Body\
	$cmd .= "-F '=(;;type=multipart/alternative' ";;\
	\
	# Leerzeichen und <br> bzw <br \> am Anfang entfernen:\
	$message =~ s/^(\s|<br(?:[ \/]+)>)+//;;\
	# Leerzeichen und <br> bzw <br \> am Ende entfernen:\
	$message =~ s/(\s|<br(?:[ \/]+)>)+$//;;\
	\
	#Plaintext E-Mail Inhalt an cURL:\
	$cmd .= "-F \"=$message;;type=text/plain;; charset=UTF-8\" ";;\
	#ersetze \n bzw. \r\n durch ein HTML-tag <br />:\
	$message =~ s/\r?\n/<br \/>/g;;\
	\
	#HTML E-Mail Inhalt an cURL:\
	$cmd .= "-F '= <body>$message</body>;;type=text/html;; charset=UTF-8' ";;\
	$cmd .= "-F '=)' ";;\
	\
	#jetzt alle Attachments (0..N) anhängen:\
	foreach my $file (@attachments) {\
		$cmd .= "-F '=@".$file.";;encoder=base64' ";;\
	}\
	\
	#stderr auch mit in den output sammeln:\
	$cmd .= " 2>&1";;\
	\
	#Blockierender Aufruf von cURL in dieser Funktion via BlockingCall:\
	if (!defined &sendMailfunc1) {\
		*sendMailfunc1 = sub ($) {\
			my ($param) = @_;;\
			my $result;;\
			$result = qx/$param/;;\
			$result = MIME::Base64::encode_base64($result);;\
			$result =~ s/\n//g;;\
			return $result;;\
		}\
	}\
	\
	#Rückgabe über diese Funktion,\
	#anzeigen in dem reading dieses UserReadings:\
	if (!defined &sendMailfunc2) {\
		*sendMailfunc2 = sub ($) {\
			my ($result) = @_;;\
			my $hash = $defs{$name};;\
			$result = MIME::Base64::decode_base64($result);;\
			readingsSingleUpdate($hash, $reading, $result, 1);;\
		}\
	}\
	\
	#funktion falls BlockingCall abgebrochen wird:\
	if (!defined &sendMailfunc3) {\
		*sendMailfunc3 = sub ($) {\
			my ($result) = @_;;\
			my $hash = $defs{$name};;\
			readingsSingleUpdate($hash, $reading, $result, 1);;\
		}\
	}\
	\
	BlockingCall("sendMailfunc1", $cmd, "sendMailfunc2", 20, "sendMailfunc3", "Error: timeout");;\
	\
	return "started cURL command...";;\
},\
state:password:.* {\
	# Passwort speichern\
	my $ret = setKeyValue("${name}_password", ReadingsVal($name, 'password', undef)) // "password stored";;\
	\
	#password wieder aus der Variablen rausnehmen, soll nicht sichtbar bleiben:\
	#\
	# Hinweis: das Password taucht beim Setzen hierüber im Event-Log auf!\
	# Alternativ: { setKeyValue("sendMail_password", "geheimesPasswort") }\
	readingsBulkUpdate($hash, "password", "****");;\
	\
	return "$ret";;\
}

Das Passwort setzt man mit:

  • set sendMail password geheimesPasswort
  • Alternativ, damit das Passwort nicht im Log auftaucht: { setKeyValue("sendMail_password", "geheimesPasswort") }

E-Mails kann man dann Senden mit:

  • set sendMail message Mein Text (es wird der Standardbetreff und Empfänger aus dem Snippet genutzt)
  • set sendMail message Betreff="Mein Betreff" Mein Text(es wird der Empfänger aus dem Snippet genutzt)
  • set sendMail message Subject="Dies ist ein Test" Mein Text
  • set sendMail message To="jemand@example.com" Mein Text
  • set sendMail message An="jemand@example.com" Mein Text
  • set sendMail message An="jemand@example.com" Betreff="Mein Betreff" Mein Text
  • set sendMail message To="jemand@example.com" Subject="Mein Betreff" Mein Text
  • set sendMail message Subject="✅ Dies ist ein Test" Meldung mit Emoji ⚽ geht auch
  • Eine Datei mit anhängen: set sendMail message Subject="Dies ist ein Test" Anhang="www/images/fhemSVG/bag.svg" Mein Text
  • Zwei Dateien mit anhängen: set sendMail message Subject="Dies ist ein Test" Anhang="./www/images/fhemSVG/bag.svg" Anhang="www/images/fhemSVG/batterie.svg" Mein Text, für die anzuhängenden Dateien können relative und absolute Pfade verwendet werden. Beim Vorbereiten der E-Mail wird geprüft ob die Dateien existieren, da dies sonst eine typische Fehlerquelle ist. Es wird nichts versendet wenn eine Datei nicht gefunden werden kann.

Fehlersuche

Sollte cURL zwar installiert sein, aber keine E-Mails versenden, kann es sein, dass das Protokoll nicht einkompiliert wurde. Dies ist bei OpenWRT zum Beispiel der Fall.

So sollte es aussehen (hier ein Ubuntu), relevant ist für diese Nutzung das Protokoll smtp und smtps, das braucht man:

curl -V
curl 8.5.0 (x86_64-pc-linux-gnu) libcurl/8.5.0 OpenSSL/3.0.13 zlib/1.3 brotli/1.1.0 zstd/1.5.5 libidn2/2.3.7 libpsl/0.21.2 (+libidn2/2.3.7) libssh/0.10.6/openssl/zlib nghttp2/1.59.0 librtmp/2.3 OpenLDAP/2.6.7
Release-Date: 2023-12-06, security patched: 8.5.0-2ubuntu10.6
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM PSL SPNEGO SSL threadsafe TLS-SRP UnixSockets zstd

So sollte es nicht aussehen (hier ein OpenWRT):

curl: (1) Protocol "smtps" not supported

curl -V
curl 8.10.1 (arm-openwrt-linux-gnu) libcurl/8.10.1 mbedTLS/3.6.2 nghttp2/1.63.0
Release-Date: 2024-09-18
Protocols: file ftp ftps http https ipfs ipns mqtt
Features: alt-svc HSTS HTTP2 HTTPS-proxy IPv6 Largefile SSL threadsafe UnixSockets

Hat man nur ein cURL ohne das Protokoll, so muss man sich das Paket leider anderweitig beschaffen (chroot, selbst kompilieren, statisch gelinkte Version, ...).

Forumlink

https://forum.fhem.de/index.php?topic=140814.0

EXIM4 (Debian)

Eine Anleitung zum Versenden von E-Mails mit Exim ist als PDF verfügbar: PDF

SSMTP (OpenWRT, embedded Distros)

Installation

opkg update
opkg install ssmtp_2.64-4_mpc85xx.ipk

Damit ssmtp funktioniert müssen die Dateien /etc/ssmtp/ssmtp.conf und /etc/ssmtp/revaliases angepasst werden.

/etc/ssmtp/ssmtp.conf

 root=arnold@gmx.net
 mailhub=mail.gmx.net:465
 rewriteDomain=gmx.net
 hostname=gmx.net
 FromLineOverride=YES
 UseTLS=YES
 #UseSTARTTLS=YES
 AuthUser=arnold@gmx.net
 AuthPass=Passwort_von_arnold@gmx.net

/etc/ssmtp/revaliases

 root:arnold@gmx.net:mail.gmx.net:465

In der 99_myUtils folgende Unterroutine einfügen:

sub OpenWRTMail 
{ 
 my $rcpt = shift;
 my $subject = shift; 
 my $text = shift; 
 my $ret = "";
 my $sender = "dockstar\@heye-tammo.de"; 
 Log 1, "sendEmail RCP: $rcpt, Subject: $subject, Text: $text";
 $ret .= qx(echo -e 'to:$rcpt\n from:$sender\nsubject:$subject\n$text\n' | ssmtp $rcpt);
 $ret =~ s,[\r\n]*,,g;    # remove CR from return-string 
 Log 1, "sendEmail returned: $ret"; 
}

PHP Mail Funktion (Synology DiskStation)

Beim DSM 3.2 funktioniert der php-mail-Befehl, so dass man mittels folgendem Modul E-Mails versenden kann:

sub sendmail($$$) {
 my($empf, $subj, $nachricht) = @_;
 system("php -r 'mail(\"$empf\",\"$subj\",\"$nachricht\");'");
}

Sendemail (Veraltet, Debian-basierende Distros)

Es handelt sich um ein Perl Programm, dass man aus den Paketquellen installieren kann.

Es gibt Probleme:

weswegen diese Lösung als technisch überholt gelten sollte. Will man trotzdem sendemail verwenden folgenden hier die Informationen dazu:

Auf dem Server muss sendemail installiert werden:

sudo apt-get update
sudo apt-get install sendemail libio-socket-ssl-perl libnet-ssleay-perl perl

Man kann die korrekte Funktion im Terminal (ohne {qx()} ) oder auch in der FHEM Kommandozeile testen (Hinweis: manche Provider (z.B. gmail) lassen diesen Zugang erst nach Freischaltung zu!).

Bei Gmail muss seit dem 30.6.2022 ein separates Passwort erzeugt werden, die alte Einstellung über "Zugriff durch weniger sichere Apps" funktioniert nicht mehr. Siehe Support Seite Google: https://support.google.com/accounts/answer/185833

Beispiel mit Gmail über Linux Terminalfenster:

sendemail -f 'Der.Absender@gmail.com' -t 'Der.Empfaenger@gmail.com' -u 'subject' -m 'text' -a '' -s 'smtp.gmail.com:587' -xu 'Der.Absender' -xp DASSUPERGEHEIMEPASSW0RT

In der 99_myUtils folgende Unterroutine einfügen:

######## DebianMail  Mail auf dem RPi versenden ############ 
# $provider für SMTP Server anpassen. 
# Einmal in der FHEM Kommandozeile, user und password anpassen:
# {setKeyValue("myEmailKonto",'user@domain');;setKeyValue("myEmailPasswrd",'password')}
sub DebianMail 
{ 
 my $rcpt = shift;
 my $subject = shift; 
 my $text = shift; 
 my $attach = shift; 
 my $ret = "";
 my $error;
 my $konto = getKeyValue("myEmailKonto"); 
 my $passwrd = getKeyValue("myEmailPasswrd"); 
 my $from = $konto; # or use different KeyValue if konto is not the from email address
 my $provider = "smtp.1und1.de"; # smtp.domain.tld:port see provider documentation
 #Log 1, "sendEmail RCP: $rcpt";
 #Log 1, "sendEmail Subject: $subject";
 #Log 1, "sendEmail Text: $text";
 #Log 1, "sendEmail Anhang: $attach";
 if (not defined($attach)){$attach=''}
 $ret .= qx(sendemail -f '$from' -t '$rcpt' -u '$subject' -m '$text' -a $attach -s '$provider' -xu '$konto' -xp '$passwrd' -o tls=auto -o message-charset=utf-8);
 $ret =~ s,[\r\n]*,,g;    # remove CR from return-string 
 Log 1, "sendemail returned: $ret"; 
}
###############################################################################

Die Zugangsdaten für den Email-Account müssen dabei FHEM-intern gespeichert werden. Dazu gibt man einmalig über die Kommandozeile folgendes ein (user@domain und password müssen auf den Email Account geändert werden):

{setKeyValue("myEmailKonto",'user@domain');;setKeyValue("myEmailPasswrd",'password')}

Um die TLS Verschlüsselung (ehem. SSL) nicht zu nutzen, muss in der viertletzten Zeile tls=no verwendet und der Port des Mailproviders auf 25 eigetragen werden. Sollte anschließend keine Mail verschickt werden, siehe Probleme.

Falls der Body-Text in einem (Android-)Mailer auf dem Handy nicht gezeigt wird, kann der Parameter -o message-content-type=html helfen.

Die Funktion kann beispielsweise folgendermaßen aufgerufen werden:

{qx(sendemail -f 'Ab\@send.er' -t 'Emp\@faeng.er' -u 'subject' -m 'text' -a 'DateinameOderLeer' -s 'smtpFQDN:port' -xu 'MailUser' -xp 'PasswortOhneKlammeraffen')}

Bei allen Feldern können generell doppelte " oder einfache ' Anführungszeichen verwendet werden. Innerhalb von "" müssen Sonderzeichen wie @ aber maskiert werden, da sie sonst als Steuerzeichen interpretiert werden:

"email\@email.domain" oder 'email@email.domain'

Direkt in der FHEM Kommandozeile (ohne Anhang)

{DebianMail("email\@email.domain","Subject","Text")}

Die ordnungsgemäße Ausführung wird mit 71 quittiert.

Beispiele mehrere Anhänge (Es ist wichtig Dateinamen mit Leerzeichen in separate Anführungszeichen zu setzen)

{DebianMail("email\@email.domain","Subject","Text","Anhang1 Anhang2 Anhang3")}
{DebianMail('email@email.domain','Subject','Text',"'with spaces Anhang1' 'with spaces Anhang2'")}

oder (mehr als einen Empfänger, diese können durch Leerzeichen, Semikolon oder Komma getrennt sein)

define Sonstiges at *01:00:00 {\
DebianMail('email@email.domain,email2@email.domain',"Subject","Text","'Anhang1' 'Anhang2' ...");;\
}

Die archivierte Doku zu sendemail befindet sich in der Änderungshistorie: https://wiki.fhem.de/w/index.php?title=E-Mail_senden&oldid=37524