The other day, for debugging purposes, I needed to deploy a dummy SMTP server that would receive, log and NOT send emails. There’s actually a cool little Python one-liner that does something similar to this:
Bam. A basic SMTP server that will output messages to stdout. Note that since it’s a port less than 1024, we need to run this command as sudo or in an administrative command prompt in order to bind to port 25.
Before I continue, I wan’t to make you aware that I’ve never scripted in Python before. This was my first application (Yeah, screw you, “Hello World”) So I lack experience, and some of my solutions may be inefficient and bad practice. (Please let me know if so!)
For my application, the downside of the previous command is that it only outputs to stdout and does not run as a service (I was looking for more of a permanent solution for debugging / dev purposes… a lot of debugging.)
As a “solution” I wrapped a derivative of this command into a Windows Service using a Python extension called pywin32.
Here’s what I came up with:
In order to install this service, you’d execute:
Now if you go to services, you can see that there’s a new service called “SMTP Dummy Server” (As specified in line 15) You can now start and stop this service at will and it will act as an SMTP server that will save all emails to the
C:\DummySMTP\ folder with daily rotating log files.
One issue was that in order for the server to keep polling for incoming messages, you need to execute
asyncore.loop() – The problem is that when executed, it locks and we can no longer do anything. Unfortunately there is no “clean” way to quit out of this. (So what do we do if the user tells the service to stop?) One way to have it end naturally is to close all open channels as per the documentation.
The service also needs to wait for a stop command. This is done through this:
Which waits until a stop event. (Or any event change, I believe) Meaning: yay, more threads!
On top of this, I wanted to log to file so I needed to have a loop that redirected stdout to file. Those two issues were solved like so:
Now we’re free to execute our logging commands
This just keeps looping until the myStatusThread is no longer alive. Once no longer alive, the smtpd server is closed and the asyncoreThread is joined. The asyncoreThread should naturally close due to us closing all open channels and the Windows Service reports a clean service stop.