E-Mail PDF-Anhang speichern – Python-Script für ecoDMS Übergabe

Nachdem ich zuhause das DMS-System aufgesetzt und meine ganzen Dokumente digitalisiert habe stand das Thema der PDF-Dokumente welche per Mail reinkommen auf dem Plan. Ein Script welches mir E-Mail PDF-Anhang speichern kann musst her.

Archivierung von Rechnungen aus E-Mails

Egal wo man heute etwas bestellt, meist kommen die Rechnungen in elektronischer Form. Doch wie kann ich diese Rechnungen nun am Einfachsten in meinem DMS-System archivieren? Eigentlich ging ich davon aus dass ein System wie z.B. ecoDMS ein solches E-Mail Gateway automatisiert mitliefert, leider war dies jedoch nicht der Fall.

Somit musste eine eigene Lösung her. Kein Problem, ein kleines Script sollte das Problem schnell Lösen. Die Grundidee: Ich erzeuge mir ein Mailpostfach an welches ich alle E-Mails, deren PDF-Anhänge archiviert werden sollen weiterleite. Dieses Postfach wird von einem Cronjob abgeholt, die PDF-Anhänge aus den Mails heruntergeladen und in den Übergabeordner von ecoDMS gelegt.

Nach einigen Versuchen ist das folgende Python-Script entstanden welches bei mir nun schon seit über 2 Jahren produktiv im Einsatz ist und stabil seinen Dienst verrichtet.

E-Mail PDF-Anhang speichern – Python-Script

#!/usr/bin/env python
"""
importDmsMails.py
Check emails at :const:`PROVIDER` for attachments and save them to
:const:`SAVEDIR`.
"""
from __future__ import absolute_import, division, print_function
import email
import os
import poplib
PROVIDER = 'XXXX'
USER = 'XXXX'
PASSWORD = 'XXXX'
SAVE_DIR = '/opt/ecodms/workdir/scaninput/'
def getNotExistingFileName(saveDir, srcFileName):
counter = 1
if (srcFileName.endswith("pdf?=")):
srcFileName = "scanbymail.pdf"
while (True):
currentName = srcFileName
if (counter > 1):
currentName = str(counter) + "_" + srcFileName
if (os.path.isfile(saveDir + currentName)):
counter = counter + 1
else:
return currentName
def save_attachments(mail_string):
attachments = list()
for part in email.message_from_string(mail_string).walk():
name = part.get_filename()
if name:
print('Handle Attachment {0!r}.'.format(name))
if name.lower().endswith(("pdf", "pdf?=")):
data = part.get_payload(decode=True)
name = name.replace("/", "_")
targetFileName = getNotExistingFileName(SAVE_DIR, name)
f = file(os.path.join(SAVE_DIR, targetFileName), 'wb')
f.write(data)
f.close()
print('Found and saved attachment {0!r}.'.format(targetFileName))
def main():
try:
client = poplib.POP3_SSL(PROVIDER)
client.user(USER)
client.pass_(PASSWORD)
message_numbers = (int(s.split()[0]) for s in client.list()[1])
for message_number in message_numbers:
save_attachments('\n'.join(client.retr(message_number)[1]))
client.dele(message_number)
finally:
client.quit()
if __name__ == '__main__':
main()

Was genau tut das Script?

Das hier aufgeführte Python-Script wird bei mir regelmäßig durch einen Cronjob ausgeführt. Das Script verbindet sich zu meinem Mailserver und lädt sich alle Mails herunter. Hängt an einer Mail ein PDF-Anhang so wird dieser Anhang im Eingangsverzeichnis von ecoDMS gesichert. Bei der Speicherung der Datei prüft das Script ob hier bereits eine Datei mit gleichem Namen vorliegt. Ist dies der Fall so wird der Dateiname durch einen Zähler erweitert so dass keine bereits existierende Datei überschrieben wird.

Wer möchte kann das Script natürlich gerne verwenden und auf seine Bedürfnisse anpassen. Natürlich übernehme ich keine Garantie für die Funktion des Scriptes, die Verwendung erfolgt auf eigene Gefahr 🙂

Update – 11. Juni 2021

Ich habe gestern eine Mail erhalten welche mich auf ein Problem hinwies. Thomas erhielt beim Ausführen des Scriptes den folgenden Fehler:

python3 importDmsMails.py
Traceback (most recent call last):
File "importDmsMails.py", line 61, in <module>
main()
File "importDmsMails.py", line 54, in main
save_attachments('\n'.join(client.retr(message_number)[1]))
TypeError: sequence item 0: expected str instance, bytes found

Bei der Analyse der Meldung stellte sich heraus, dass ich eine andere Python-Version als Thomas verwende. Bei mir läuft Python in der Version 2.7.10, bei ihm auf Python 3. Die Ursache für den Fehler liegt wohl in einer Anpassung in Python welche dafür sorgt, dass der Befehl “join” nicht mehr einen String und Bytes konfigurieren kann. Dies kann relativ einfach gefixt werden:

Alt: save_attachments('\n'.join(client.retr(message_number)[1]))
Neu: save_attachments(b'\n'.join(client.retr(message_number)[1]))
Artikel teilen

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.