1# -*- coding: utf-8 -*- 2import asyncore 3import sys 4from logging import getLogger 5from smtpd import SMTPServer 6 7from django.core.management.base import BaseCommand, CommandError 8 9from django_extensions.management.utils import setup_logger, signalcommand 10 11logger = getLogger(__name__) 12 13 14class ExtensionDebuggingServer(SMTPServer): 15 """Duplication of smtpd.DebuggingServer, but using logging instead of print.""" 16 17 # Do something with the gathered message 18 def process_message(self, peer, mailfrom, rcpttos, data, **kwargs): 19 """Output will be sent to the module logger at INFO level.""" 20 inheaders = 1 21 lines = data.split('\n') 22 logger.info('---------- MESSAGE FOLLOWS ----------') 23 for line in lines: 24 # headers first 25 if inheaders and not line: 26 logger.info('X-Peer: %s' % peer[0]) 27 inheaders = 0 28 logger.info(line) 29 logger.info('------------ END MESSAGE ------------') 30 31 32class Command(BaseCommand): 33 help = "Starts a test mail server for development." 34 args = '[optional port number or ippaddr:port]' 35 36 requires_system_checks = False 37 38 def add_arguments(self, parser): 39 super().add_arguments(parser) 40 parser.add_argument( 41 '--output', dest='output_file', default=None, 42 help='Specifies an output file to send a copy of all messages (not flushed immediately).' 43 ) 44 parser.add_argument( 45 '--use-settings', dest='use_settings', 46 action='store_true', default=False, 47 help='Uses EMAIL_HOST and HOST_PORT from Django settings.' 48 ) 49 50 @signalcommand 51 def handle(self, addrport='', *args, **options): 52 if not addrport: 53 if options['use_settings']: 54 from django.conf import settings 55 addr = getattr(settings, 'EMAIL_HOST', '') 56 port = str(getattr(settings, 'EMAIL_PORT', '1025')) 57 else: 58 addr = '' 59 port = '1025' 60 else: 61 try: 62 addr, port = addrport.split(':') 63 except ValueError: 64 addr, port = '', addrport 65 if not addr: 66 addr = '127.0.0.1' 67 68 if not port.isdigit(): 69 raise CommandError("%r is not a valid port number." % port) 70 else: 71 port = int(port) 72 73 # Add console handler 74 setup_logger(logger, stream=self.stdout, filename=options['output_file']) 75 76 def inner_run(): 77 quit_command = (sys.platform == 'win32') and 'CTRL-BREAK' or 'CONTROL-C' 78 print("Now accepting mail at %s:%s -- use %s to quit" % (addr, port, quit_command)) 79 ExtensionDebuggingServer((addr, port), None, decode_data=True) 80 asyncore.loop() 81 82 try: 83 inner_run() 84 except KeyboardInterrupt: 85 pass 86