3 import asynchat as _asynchat
4 import socket as _socket
6 from pgp_mime import email as _email
8 from .. import LOG as _LOG
11 class MessageSender (_asynchat.async_chat):
12 """A SMTP message sender using ``asyncore``.
14 To test ``PygraderServer``, it's useful to have a message-sender
15 that also uses ``asyncore``. This avoids the need to use
18 def __init__(self, address, messages):
19 super(MessageSender, self).__init__()
20 self.address = address
21 self.messages = messages
22 self.create_socket(_socket.AF_INET, _socket.SOCK_STREAM)
27 self.set_terminator(b'\r\n')
29 self.callback = (self.send_message, [], {})
31 self.callback = (self.quit_callback, [], {})
32 self.send_command('ehlo [127.0.0.1]')
34 def log_info(self, message, type='info'):
35 # TODO: type -> severity
38 def send_command(self, command, clear_command_list=True):
39 if clear_command_list:
40 self.commands = [command]
42 _LOG.debug('push: {}'.format(command))
43 self.push(bytes(command + '\r\n', 'ascii'))
45 def send_commands(self, commands):
46 self.commands = commands
48 for command in self.commands:
49 self.send_command(command=command, clear_command_list=False)
51 def collect_incoming_data(self, data):
52 self.ibuffer.append(data)
54 def found_terminator(self):
55 ibuffer = b''.join(self.ibuffer)
57 self.ilines.append(ibuffer)
58 if len(self.ilines[-1]) >= 4 and self.ilines[-1][3] == ord(b' '):
59 response = self.ilines
61 self.handle_response(response)
63 def handle_response(self, response):
64 _LOG.debug('handle response: {}'.format(response))
65 code = int(response[-1][:3])
67 self.intro = (code, response)
69 self.responses.append((code, response))
70 if len(self.responses) == len(self.commands):
72 callback,args,kwargs = self.callback
74 commands = self.commands
76 responses = self.responses
78 _LOG.debug('callback: ({}, {})'.format(callback, list(zip(commands, responses))))
79 callback(commands, responses, *args, **kwargs)
83 def close_callback(self, commands, responses):
88 def quit_callback(self, commands, responses):
89 self.send_command('quit')
90 self.callback = (self.close_callback, [], {})
92 def send_message(self, commands, responses):
93 message = self.messages.pop(0)
95 self.callback = (self.send_message, [], {})
97 self.callback = (self.quit_callback, [], {})
98 sources = list(_email.email_sources(message))
100 'mail FROM:<{}>'.format(sources[0][1])
102 for name,address in _email.email_targets(message):
103 commands.append('rcpt TO:<{}>'.format(address))
106 message.as_string() + '\r\n.',
108 self.send_commands(commands=commands)