How to capture output from Python smtp debug server

django, email, python

Solution

I had the same problem and spent 2 days trying to figure out what's going on. I tried running both

python -m smtpd -n -c DebuggingServer localhost:1025

and

python -m smtpd -n -c DebuggingServer localhost:1025 > mail.log

from one of my integration tests with `subprocess`, but it didn't work. While experimenting with it through REPL I noticed that first read from the pipe that is opened for us by `subprocess` hangs. After I kill it, next read actually returns the data. So I started investigating what's in the stream. But as I had no luck in 2 hours, I ended up rolling my own wrapper around `SMTPServer` that writes to the file, and got myself up and running.

Here is the wrapper class (`process_message` is an abstract method that is required of `smtpd.SMTPServer`'s child class to be runnable by `smtpd` module):

# test_smtpd.py

import smtpd

SMTP_DUMPFILE = '/tmp/mail.log'

class SMTPTestServer(smtpd.SMTPServer):
    def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
        with open(SMTP_DUMPFILE, 'w') as f:
            f.write(data)

I run it with

python -m smtpd -n -c test_smtpd.SMTPTestServer localhost:1025

While this does not directly answer your question, it is an easy workaround, so I hope this helps.

Problem

I'm trying to write unittests for some custom Django email backends, and to test it against a "real" smtp server, I'm trying to use Python's built-in smtpd debugging server by running: ``` python -m smtpd -n -c DebuggingServer localhost:1025 ``` My unittest basically looks like: ``` class Tests(TestCase): @override_settings(EMAIL_BACKEND='mycustombackend') @override_settings(EMAIL_HOST='localhost') @override_settings(EMAIL_PORT='1025') def test_backend(self): from django.core import mail mail.send_mail( subject='Subject here', message='Here is the message.', from_email='from@example.com', recipient_list=['to@example.com'], fail_silently=False, ) ``` and when I run this, the smtpd process outputs the email content correctly. However, when I try and capture that so I can confirm it in my unittest, I get nothing. I've tried using the `subprocess` package, to launch the process and read the output via pipes, but it never receives any output. I thought I was using subprocess incorrectly, so as a last resort, I tried launching the process with: ``` python -m smtpd -n -c DebuggingServer localhost:1025 > /tmp/smtpd.log ``` and reading the log file. However, even with that, no output is ever written to the file. What's going on here?

Original source