Als Mailsystem auf dem Raspberry habe ich mutt eingerichtet. Ich habe das hauptsächlich durch https://www.sbprojects.net/projects/raspberrypi/mutt.php gelernt.
Achtung: ich habe viele Befehle so beschrieben, dass sie als ‚root‚ User durchgeführt werden müssen. Sie können natürlich auch mit ‚sudo‚ ausgeführt werden, doch Vorsicht bei Kommandos, die auf den vorherigen aufbauen, z.B. via cd.
Also als root:
apt-get install mutt # installation des mutt Packets
Der einzelne User muss nun für sich folgendes anlegen:
mkdir -p ~/.mutt/cache/headers
mkdir -p ~/.mutt/cache/bodies
touch ~/.mutt/certificates
Lege auch noch die Datei .muttrc im $HOME Directory an, mit folgendem Inhalt (Beispiel für einen Mail Account beim Provider 1blu):
vi .muttrc
# A basic .muttrc for use with Gmail
# Change the following six lines to match your Gmail account details
set imap_user = "account name"
set imap_pass = "PASSWORD"
set smtp_url = "smtps://accountname@smtp.1blu.de:465/"
set smtp_pass = "PASSWORD"
set from = "from@address"
set realname = "YOUR NAME"
# Change the following line to a different editor you prefer.
set editor = "nano"
# Basic config, you can leave this as is
set folder = "imaps://imap.1blu.de:993"
set spoolfile = "+INBOX"
set imap_check_subscribed
set hostname = 1blu.de
set mail_check = 120
set timeout = 300
set imap_keepalive = 300
set postponed = "+[1blu]/Drafts"
set record = "+[1blu]/Sent Mail"
set header_cache=~/.mutt/cache/headers
set message_cachedir=~/.mutt/cache/bodies
set certificate_file=~/.mutt/certificates
set move = no
set include
set sort = 'threads'
set sort_aux = 'reverse-last-date-received'
set auto_tag = yes
ignore "Authentication-Results:"
ignore "DomainKey-Signature:"
ignore "DKIM-Signature:"
hdr_order Date From To Cc
alternative_order text/plain text/html *
auto_view text/html
bind editor <Tab> complete-query
bind editor ^T complete
bind editor <space> noop
# Gmail-style keyboard shortcuts
macro index,pager y "<enter-command>unset trash\n <delete-message>" "Gmail archive message"
macro index,pager d "<enter-command>set trash=\"imaps://imap.googlemail.com/[GMail]/Bin\"\n\
<delete-message>" "Gmail delete message"
macro index,pager gi "<change-folder>=INBOX<enter>" "Go to inbox"
#macro index,pager ga "<change-folder>=[Gmail]/All Mail<enter>" "Go to all mail"
#macro index,pager gs "<change-folder>=[Gmail]/Starred<enter>" "Go to starred messages"
#macro index,pager gd "<change-folder>=[Gmail]/Drafts<enter>" "Go to drafts"
#end-----------------------------------------
Nun kann man Mails aus der oben konfigurierten Mailbox mit dem Kommando mutt abrufen.
Auch Mails mittels Kommandline kann man verschicken. Man muss allerdings mutt in eine Pipe einbauen, sonst öffnet sich die Ascii Oberfläche von mutt.
echo "der Text, der verschickt wird" | mutt -c 'ccbox@domain' 'box@domain' -s "Subject Text" -a "Datei zum Anhängen"
Verschickt eine Mail an box als Hauptadressat und ccbox unter cc, mit Inhalt, Betreff und Anhang.
cat textdatei.txt | mutt -c 'ccbox@domain' 'box@domain' -s "Subject Text" -a "Datei zum Anhängen"
Und wie empfange ich Mail? Wie oben beschrieben, geht das mit der Ascii Oberfläche von mutt. Aber wie geht das innerhalb eines Scripts, wo man programmieren will, um gezielt Mails zu lesen? Diese in ein bash Script einzubauen, ist mir mit mutt nicht gelungen.
Mittels python geht es!
Lege folgende Datei an:
# job to read from a mail box and if in Betreff is a command, execute it
import imaplib
import email
from email.header import decode_header
import webbrowser
import os
# account credentials
# username = "youremailaddress@provider.com"
username = "your primary email name, not an alias"
password = "unfortuantely in clear text"
# should be replaced later by number from hostname
hostdigit = 2
# clean text for creating a folder
def clean(text):
return "".join(c if c.isalnum() else "_" for c in text)
print ("step 1")
# create an IMAP4 class with SSL
#imap = imaplib.IMAP4_SSL("imap.gmail.com")
imap = imaplib.IMAP4_SSL("imap.1blu.de",993)
# authenticate
imap.login(username, password)
# print ("step 2")
# now get the mails
status, messages = imap.select("INBOX")
# number of top emails to fetch
N = 3
# total number of emails
messages = int(messages[0])
print ("messages:",messages)
# get the new one first - else use range(N)
# start stop step
for i in range(1,messages+1,1): # get all mails
#for i in range(messages, messages-N, -1): # get only N last mails
print ("-----------------------")
print ("new mail found at i =",i)
if i == 0 or i == 9999: # here you can give a limit, here 9999
print ("exit by limit")
break
# fetch the email message by ID
res, msg = imap.fetch(str(i), "(RFC822)")
for response in msg:
if isinstance(response, tuple):
# parse a bytes email into a message object
newmsg = email.message_from_bytes(response[1]) #--> help (email)
# decode the email subject
subject, encoding = decode_header(newmsg["Subject"])[0]
if isinstance(subject, bytes):
# if it's a bytes, decode to str
subject = subject.decode(encoding)
# decode email sender
From, encoding = decode_header(newmsg.get("From"))[0]
if isinstance(From, bytes):
From = From.decode(encoding)
print("Subject:", subject)
print("Subject >"+subject[0:16]+'<')
print("From:", From)
# 0123456789012345
if subject[0:16] == "CMD: Temperature":
# extract content type of email
content_type = newmsg.get_content_type()
# get the email body -
# see https://docs.python.org/3.7/library/email
# see https://docs.python.org/3.7/library/email.generator.html#email.generator.Generator
body = newmsg.get_payload
print("body",body)
# print ("subject again:",subject);
subteil=subject.partition("CMD" + str(hostdigit) + ":")
print("all:",subteil)
print("only1:",subteil[1])
if newmsg.get_content_maintype() == 'multipart':
print ("Multipart")
# print(newmsg.as_string())
# everything is in as_string ...
# print (myline)
if 1 == 1: # you can skip more analysis
# 1 2 3 4 5
# 12345678901234567890123456789012345678901234567890
# Subject: CMD: Temperature Summary on 210919_235901
print("Subject Date>"+subject[28:39]+'<')
fileName = "DHT22_"+subject[28:39]+"_full.txt"
filePath = os.path.join('/home/nfl/scripts/', fileName)
print ("filePath:",filePath)
if not os.path.isfile(filePath):
print ("before write")
fp = open(filePath, 'wb')
fp.write(bytes(newmsg.as_string(),'UTF-8'))
fp.close()
else:
print ("no write")
continue
if newmsg.get('Content-Disposition') is None:
print ("Content")
print(msg.as_string())
continue
fileName = newmsg.get_filename()
print ("fileName:",fileName)
if bool(fileName):
filePath = os.path.join('./scripts/', fileName)
print ("filePath:",filePath)
if not os.path.isfile(filePath) :
fp = open(filePath, 'wb')
fp.write(msg.get_payload(decode=True))
fp.close()
# close the connection and logout
imap.close()
imap.logout()
Aufruf dann einfach mit ‚python3 script.py‚. Obige Script macht noch mehr als nur lesen – ist ein Beispiel, wie schnell man so was mit Python machen kann.
Unerwähnt will ich nicht folgendes lassen: Gelungen war es mir schließlich zuerst mit perl! Doch diesem Packet fehlte die Auswahl der Ports beim SMDP Server! Das erlauben nicht mehr alle Provider! Deswegen oben die Version mit Python.
Also nur für die Perl Variante: Installiere cpanm, was gegenüber cpan den Vorteil hat, dass es Abhängigkeiten automatisch mit installiert.
su - # muss man also wieder als root machen!
curl -L http://cpanmin.us | /bin/perl - --self-upgrade
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 295k 100 295k 0 0 988k 0 --:--:-- --:--:-- --:--:-- 985k
--> Working on App::cpanminus
Fetching http://www.cpan.org/authors/id/M/MI/MIYAGAWA/App-cpanminus-1.7044.tar.gz ... OK
Configuring App-cpanminus-1.7044 ... OK
Building and testing App-cpanminus-1.7044 ... OK
Successfully installed App-cpanminus-1.7044
1 distribution installed
Und nun weiter perl Packete installieren mit:
cpanm Email::Date
cpanm Email::Simple
cpanm Net::IMAP
cpanm Net::IMAP::Simple
Folgender Link war noch nötig:
cd /usr/local/share/perl/
ln -s 5.28.1 5.28
ll
total 12
drwxrwxr-x 3 root root 4096 Nov 18 21:56 .
drwxr-xr-x 8 root root 4096 Nov 18 21:44 ..
lrwxrwxrwx 1 root root 6 Nov 18 21:56 5.28 -> 5.28.1
drwxrwxr-x 13 root root 4096 Nov 18 21:55 5.28.1
Nun schreibe ein Perl Programm, wie z.B. folgendes. Das liest alle Messages in der Mailbox, zeigt ihren Subject an, und löscht sie, falls dieses Statement aktiv ist.
use Net::IMAP::Simple;
use Email::Simple;
# Create the object
my $imap = Net::IMAP::Simple->new('imap.example.com') ||
die "Unable to connect to IMAP: $Net::IMAP::Simple::errstr\n";
# Log on
if(!$imap->login('user','pass')){
print STDERR "Login failed: " . $imap->errstr . "\n";
exit(64);
}
# Print the subject's of all the messages in the INBOX
my $nm = $imap->select('INBOX');
for(my $i = 1; $i <= $nm; $i++){
if($imap->seen($i)){
print "*";
} else {
print " ";
}
my $es = Email::Simple->new(join '', @{ $imap->top($i) } );
printf("[%03d] %s\n", $i, $es->header('Subject'));
print "deleting or not deleting this message\n";
# remove comment if message should be deleted:
# $imap->delete( $i );
}
$imap->quit;