2008-12-09 5 views
10

Ich bin gespannt, ob es eine einfache Möglichkeit gibt, einen IMAP-Server (a la imaplib-Modul) in Python, ohne eine Menge Arbeit zu machen.Wie verspotte ich einen IMAP-Server in Python trotz extremer Faulheit?

Gibt es eine bereits vorhandene Lösung? Im Idealfall könnte ich eine Verbindung mit dem vorhandenen IMAP-Server herstellen, einen Speicherabzug erstellen und den Pseudoserver von der eigentlichen Postfach-/E-Mail-Struktur ablaufen lassen.

einige Hintergrundinformationen in die Faulheit: Ich habe eine böse Gefühl, dass dieses kleine Skript, das ich schreiben bin im Laufe der Zeit wachsen und würde wie eine geeignete Testumgebung zu schaffen, aber wenn man bedenkt, dass es im Laufe der Zeit wachsen könnte nicht Ich möchte nicht viel arbeiten, um den Mock-Server laufen zu lassen.

Antwort

9

Ich fand es ziemlich einfach, einen IMAP-Server in verdrehten letzten Mal zu schreiben, den ich versuchte. Es bietet Unterstützung für das Schreiben von IMAP-Servern und Sie haben eine große Flexibilität.

1

Ich habe nie versucht, aber wenn ich müsste, würde ich mit dem bestehenden SMTP-Server beginnen.

+1

Link oben ist tot, neue ist wahrscheinlich https://docs.python.org/2/library/smtpd.html – sdaau

7

Wie viel davon brauchen Sie wirklich für einen Test? Wenn Sie beginnen, etwas in der Größenordnung der Komplexität eines echten Servers zu erstellen, damit Sie es bei all Ihren Tests verwenden können, sind Sie bereits falsch gelaufen. Spotten Sie einfach die Bits, die ein Test benötigt.

Versuchen Sie nicht so sehr, eine Scheinimplementierung zu teilen. Sie sollen keine Assets sein, sondern verwerfbare Bits-N-Pieces.

3

Da ich nicht etwas bequem in Python 3 für meine Bedürfnisse gefunden haben (Mail-Teil von Twisted läuft nicht in Python 3), habe ich eine kleine Mock mit asyncio, die Sie verbessern können, wenn Sie möchten:

Ich habe ein ImapProtocol definiert, das asyncio.Protocol erweitert. Dann starten Sie einen Server wie folgt aus:

factory = loop.create_server(lambda: ImapProtocol(mailbox_map), 'localhost', 1143) 
server = loop.run_until_complete(factory) 

Die mailbox_map ist eine Karte der Karte: E-Mail -> Karte von Briefkästen -> Satz von Nachrichten. So sind alle Nachrichten/Postfächer im Speicher.

Jedes Mal, wenn ein Client eine Verbindung herstellt, wird eine neue Instanz von ImapProtocol erstellt. die ImapProtocol ausführt und Antworten für jeden Client, Implementierung Fähigkeit/login/Abruf-/select/Suche/store Dann:

class ImapHandler(object): 
    def __init__(self, mailbox_map): 
     self.mailbox_map = mailbox_map 
     self.user_login = None 
     # ... 

    def connection_made(self, transport): 
     self.transport = transport 
     transport.write('* OK IMAP4rev1 MockIMAP Server ready\r\n'.encode()) 

    def data_received(self, data): 
     command_array = data.decode().rstrip().split() 
     tag = command_array[0] 
     self.by_uid = False 
     self.exec_command(tag, command_array[1:]) 

    def connection_lost(self, error): 
     if error: 
      log.error(error) 
     else: 
      log.debug('closing') 
      self.transport.close() 
     super().connection_lost(error) 

    def exec_command(self, tag, command_array): 
     command = command_array[0].lower() 
     if not hasattr(self, command): 
      return self.error(tag, 'Command "%s" not implemented' % command) 
     getattr(self, command)(tag, *command_array[1:]) 

    def capability(self, tag, *args): 
     # code for it... 
    def login(self, tag, *args): 
     # code for it... 

Dann in meinen Tests, starte ich den Server während der Installation mit:

self.loop = asyncio.get_event_loop() 
self.server = self.loop.run_until_complete(self.loop.create_server(create_imap_protocol, 'localhost', 12345)) 

Wenn ich eine neue Nachricht simulieren möchten:

imap_receive(Mail(to='[email protected]', mail_from='[email protected]', subject='hello')) 

Und es Teardown zu stoppen:

cf https://github.com/bamthomas/aioimaplib/blob/master/aioimaplib/tests/imapserver.py


EDIT: Ich hatte einen Buggy Stopp des Servers, ich schrieb es mit asyncio.Protokoll und ändern Sie die Antwort, um die Änderungen zu reflektieren

+0

Während dieser Link die Frage beantworten kann, ist es besser um die wesentlichen Teile der Antwort hier einzubeziehen und den Link als Referenz zur Verfügung zu stellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - [Aus Bewertung] (/ review/low-quality-posts/11319593) – jezrael

+0

Ok, ich mache das –

+0

Aber war es notwendig, das ernst zu stimmen? Du weißt, dass es mir egal ist, ich bin nicht der Typ, der nach SO-Punkten hetzt (hast du meine Punktzahl gesehen?), Sondern versucht Leuten zu helfen, wenn ich ein Problem hatte, das mich dazu brachte, meine Zeit zu verlieren. Ich war nicht verpflichtet, meinen Code auf GitHub zu schieben und dies zu beantworten. Diese Art von Aktion drängt mich ernsthaft dazu, SO nicht mehr zu benutzen. Meine 2 Cent –