3 import asyncore as _asyncore
6 import socket as _socket
8 from .. import LOG as _LOG
11 class SMTPChannel (_smptd.SMTPChannel):
13 super(SMTPChannel, self).close()
14 _LOG.debug('close {}'.format(self))
15 self.smtp_server.channel_closed()
18 class SMTPServer (_smptd.SMTPServer):
19 """An SMTP server for testing pygrader.
21 >>> from asyncore import loop
22 >>> from smtplib import SMTP
23 >>> from pgp_mime.email import encodedMIMEText
24 >>> from pygrader.test.client import MessageSender
26 >>> def process(peer, mailfrom, rcpttos, data):
27 ... print('peer: {}'.format(peer))
28 ... print('mailfrom: {}'.format(mailfrom))
29 ... print('rcpttos: {}'.format(rcpttos))
32 >>> server = SMTPServer(
33 ... ('localhost', 1025), None, process=process, count=3)
35 >>> message = encodedMIMEText('Ping')
36 >>> message['From'] = 'a@example.com'
37 >>> message['To'] = 'b@example.com, c@example.com'
38 >>> message['Cc'] = 'd@example.com'
39 >>> messages = [message, message, message]
40 >>> ms = MessageSender(address=('localhost', 1025), messages=messages)
41 >>> loop() # doctest: +REPORT_UDIFF, +ELLIPSIS
42 peer: ('127.0.0.1', ...)
43 mailfrom: a@example.com
44 rcpttos: ['b@example.com', 'c@example.com', 'd@example.com']
46 Content-Type: text/plain; charset="us-ascii"
48 Content-Transfer-Encoding: 7bit
49 Content-Disposition: inline
51 To: b@example.com, c@example.com
55 peer: ('127.0.0.1', ...)
56 mailfrom: a@example.com
57 rcpttos: ['b@example.com', 'c@example.com', 'd@example.com']
59 Content-Type: text/plain; charset="us-ascii"
61 Content-Transfer-Encoding: 7bit
62 Content-Disposition: inline
64 To: b@example.com, c@example.com
68 peer: ('127.0.0.1', ...)
69 mailfrom: a@example.com
70 rcpttos: ['b@example.com', 'c@example.com', 'd@example.com']
72 Content-Type: text/plain; charset="us-ascii"
74 Content-Transfer-Encoding: 7bit
75 Content-Disposition: inline
77 To: b@example.com, c@example.com
82 channel_class = SMTPChannel
84 def __init__(self, *args, **kwargs):
85 self.count = kwargs.pop('count', None)
86 self.process = kwargs.pop('process', None)
87 self.channels_open = 0
88 super(SMTPServer, self).__init__(*args, **kwargs)
90 def log_info(self, message, type='info'):
91 # TODO: type -> severity
94 def handle_accepted(self, conn, addr):
98 super(SMTPServer, self).handle_accepted(conn, addr)
99 self.channels_open += 1
101 def channel_closed(self):
102 self.channels_open -= 1
103 if self.channels_open == 0 and self.count <= 0:
104 _LOG.debug('close {}'.format(self))
107 def process_message(self, peer, mailfrom, rcpttos, data):
108 if self.count is not None:
110 _LOG.debug('Count: {}'.format(self.count))
111 _LOG.debug('receiving message from: {}'.format(peer))
112 _LOG.debug('message addressed from: {}'.format(mailfrom))
113 _LOG.debug('message addressed to : {}'.format(rcpttos))
114 _LOG.debug('message length : {}'.format(len(data)))
116 self.process(peer, mailfrom, rcpttos, data)