imapclient Mails organisieren (gmail)

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
TobiWu
User
Beiträge: 2
Registriert: Sonntag 2. Februar 2020, 13:50

Hi zusammen,

ich hab mir als kleines Helferlein ein Programm geschrieben das meine Gmail Mailbox aufräumen soll.
Grds. funktioniert das auch ganz o.k. ich habe nur ein Problem, dass ich nicht alle Mails selektiert bekomme und keine bestimmten Ordner/Labels in gmail auswählen kann.
Ich kann aber absolut nicht nachvollziehen warum nicht alle Mails selektiert werden oder muss ich weitere Ordner (außer Inbox) ansprechen.

Code: Alles auswählen

#Werbung auslesen

import imaplib
import pprint
import imapclient 
import pyzmail
from email.header import decode_header
import smtplib,email,email.encoders,email.mime.text,email.mime.base
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText


imaplib._MAXLINE = 10000000


#------------------------------------------------------------#
#Datum feslegen von wann bis wann gelsöcht wird 300/1

import datetime
from datetime import date

aktuellesDatum = date.today()
dat_since = aktuellesDatum - datetime.timedelta(days = 300)
dat_till = aktuellesDatum - datetime.timedelta(days = 1)
#------------------------------------------------------------#

#------------------------------------------------------------#

#Mailbox anmelden

imapObj = imapclient.IMAPClient('imap.gmail.com', ssl=True)
imapObj.login('meine@mail.com', 'Kennwort')

#Verzeichniss

Folder = imapObj.select_folder('Inbox', readonly=True)
print(Folder)

#Mails selektieren

Mailadresse = ['no-reply@nebenan.de', 'news@biker-boarder.de', 'hallo@my.zalando-lounge.de', "\
            "'noreply@email.ticketmaster.de', 'otto-newsletter@newsletter.otto.de', "\
            "'noreply@news.eu.dcshoes.com', 'info.eu@stance.com', 'DeineMeinung@feedback.saturn.eu', "\
            "'notification@komoot.de']

UIDS =()
Counter = 0
Mails_DEL_STAT = 0

#Loop um jede angegebene Mailadresse zu selektieren

for i in Mailadresse:
    imapObj.select_folder('INBOX', readonly=False)
    UIDS= imapObj.search(['SINCE', (dat_since), 'BEFORE', (dat_till), 'FROM', (Mailadresse[Counter])])
    Counter = Counter + 1
    print(UIDS)
    count = 0
    for i in UIDS:
        #rawMessages = imapObj.fetch(UIDS,['BODY[]', 'FLAGS'])
        #message = pyzmail.PyzMessage.factory(rawMessages[UIDS[count]][b'BODY[]'])
        UID_DEL = str(UIDS[count])
        count = count + 1
        Mails_DEL_STAT = Mails_DEL_STAT + 1
        #ab hier wird gelöscht 
        imapObj.delete_messages(UID_DEL)
        imapObj.expunge()
Danach ezeuge ich noch eine Mail mit einer Übersicht was gelöscht wurde. (die Anzahl aus "Mails_DEL_STAT")

Ich habe z.B. 5 Mails von notification@komoot.de vom 16.02. und diese würden ja in den Zeitraum Heute - 1 bis heute - 300 hinein fallen.
Diese werden aber nicht selektiert und habe keine Erklärung warum ...

Vielleicht kann jemand helfen.

VG

Tobi
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@TobiWu: Da wird so einiges importiert was überhaupt nicht verwendet wird.

Dann wird `date` aus `datetime` importiert, auf `timedelta` aber über das `datetime`-Modul zugegriffen — warum diese Inkonsistenz?

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).

Man sollte sich für eine Sprache bei den Namen entscheiden. Ich würde zu Englisch raten weil alles andere, Sprache und Bibliotheken, Englisch verwenden, und weil es weniger Probleme mit Einzahl vs. Mehrzahl gibt.

Namen sollten keine kryptischen Abkürzungen enthalten. Also beispielsweise nicht `dat` wenn man `date` meint.

Der Namenszusatz `Obj` ist in Python sinnfrei weil in Python *alles* was man an einen Namen binden kann ein Objekt ist. Da könnte/müsste man dann an jeden Namen `Obj` dran hängen. Das hat aber Null Mehrwert für den Leser.

Am Ende wird die Verbindung zum Server nicht ordentlich abgebaut. `IMAPClient`-Objekte sind Kontextmanager, dass sollte man nutzen.

Ich vermute Dein Selektionsproblem liegt an `Mailadresse` und da an den drei Adressen bei denen Du Leerzeichen eingebaut hast. Der Listeninhalt sieht wie folgt aus:

Code: Alles auswählen

In [313]: Mailadresse                                                           
Out[313]: 
['no-reply@nebenan.de',
 'news@biker-boarder.de',
 'hallo@my.zalando-lounge.de',
 '            noreply@email.ticketmaster.de',
 'otto-newsletter@newsletter.otto.de',
 '            noreply@news.eu.dcshoes.com',
 'info.eu@stance.com',
 'DeineMeinung@feedback.saturn.eu',
 '            notification@komoot.de']
Ich vermute mal das war so nicht beabsichtigt und kommt durch die komischen ``"\`` und ``"`` die da im Quelltext stehen. Mit ``"\`` startest Du ein Zeichenkettenliteral das auf der nächsten Zeile fortgesetzt wird bis zum ``"``. Und direkt danach folgt dann das Zeichenkettenliteral mit der E-Mail-Adresse. Das setzt der Compiler zu einer Zeichenkette zusammen.

Der Unsinn kann ersatzlos wegfallen. Die \ braucht man nicht weil der Compiler ”weiss” dass der Ausdruck noch nicht zuende ist solange noch Klammern offen sind die noch nicht wieder geschlossen wurden. Und die Zeichenkette in " macht einfach keinen Sinn.

Der Name `Mailadresse` für eine Liste mit *mehreren* Adressen ist schlecht.

Vor der Schleife wird `UIDS` an ein leeres Tupel gebunden was nie irgendwo benutzt wird.

`Counter` und `count` sind überflüssig weil man in den Schleifen direkt über die Objekte iterieren kann. Das machst Du ja im Grunde auch, nur ist `i` ein denkbar ungünstiger Name für eine E-Mail-Adresse und eine UID, und Du benutzt die Werte auch gar nicht.

In der Schleife immer wieder den gleichen Mail-Ordner zu selektieren macht keinen Sinn. Das kann man *einmal* *vor* der Schleife machen. Wird ja auch schon gemacht, nur mit einem unpassenden Wert für das `readonly`-Argument.

Beim `search()`-Aufruf sind unnötige runde Klammern im Argument enthalten.

Du brauchst die UID weder in eine Zeichenkette umwandeln, noch musst Du die in einer Schleife alle einzeln an `delete_messages()` übergeben. Der Methodenname legt doch schon nahe das man damit mehr als eine Nachricht pro Aufruf löschen kann.

Die gelöschten Mails kannst Du nicht einfach aufgrund der gefundenen IDs zählen weil Deine suche auch IDs von Mails findet die bereits als gelöscht markiert sind. Du musst da den Rückgabewert von `delete_messages()` berücksichtigen.

`expunge()` für jede einzelne gelöschte Mail aufzurufen ist ineffizient. Das macht man einmal am Ende der Löschaktion.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import imaplib
from datetime import date as Date, timedelta as TimeDelta

import imapclient

imaplib._MAXLINE = 10_000_000

USERNAME = "meine@mail.com"
PASSWORD = "Kennwort"
DAYS_BACK = 300
ADDRESSES = [
    "DeineMeinung@feedback.saturn.eu",
    "hallo@my.zalando-lounge.de",
    "info.eu@stance.com",
    "news@biker-boarder.de",
    "no-reply@nebenan.de",
    "noreply@email.ticketmaster.de",
    "noreply@news.eu.dcshoes.com",
    "notification@komoot.de",
    "otto-newsletter@newsletter.otto.de",
]


def main():
    with imapclient.IMAPClient("imap.gmail.com", ssl=True) as imap_client:
        imap_client.login(USERNAME, PASSWORD)
        print(imap_client.select_folder("INBOX"))

        today = Date.today()
        date_since = today - TimeDelta(days=DAYS_BACK)
        date_till = today - TimeDelta(days=1)
        deleted_mail_count = 0
        for address in ADDRESSES:
            message_ids = imap_client.search(
                ["SINCE", date_since, "BEFORE", date_till, "FROM", address]
            )
            print(message_ids)
            deleted_mail_count += len(imap_client.delete_messages(message_ids))

        imap_client.expunge()

    print(deleted_mail_count)


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
TobiWu
User
Beiträge: 2
Registriert: Sonntag 2. Februar 2020, 13:50

Hi cool,

vielen Dank ich hätte nicht mit so ner ausführlichen Analyse gerechnet.

Ich werd die Optimierungsparts auf jeden Fall einbauen. Jetzt wo ich deinen Code sehe ist das wesentlich einfacher und überschaubarer wie das was ich zusammengebaut.
Zu Beginn wollte ich immer noch die Subjects aus den Mails auslesen um zu sehen was ich da löschen da kam dann das ganze Gefrickel mit den Tupels her.

Vielen Dank nochmal

Tobi
Antworten