May 12, 2015 by Daniel P. Clark

Fake a SMTP Server with Python for Rails Testing

So I’ve been in the process of writing an integration test to verify the flow of registration through some unique conditions.  One thing I ran into while writing my Rails test was this error.

Connection refused – connect(2) for nil port 25

After looking around at documentation on what to do for testing it seemed that everything was as it should be except my test environment wasn’t bypassing the actual sending of email which lead to this error.  Since I couldn’t find the answer with any Rails, S.O., or github.com/mikel/mail documentation on a quick fix I decided to use a dummy SMTP server.

I didn’t want to keep any mail sent, so this question http://serverfault.com/questions/207619/how-to-setup-a-fake-smtp-server-to-catch-all-mails had an excellent answer with Python.  It seems Python has a smtpd debugging feature which just prints incoming SMTP email out to STDOUT.

sudo python -m smtpd -n -c DebuggingServer localhost:25

Now I don’t want to have to type this every time I run my Rails test suite so I need to have my computer start with this running in the background.  On Ubuntu that was rather simple to do by creating a text file in /etc/init.d , making it executable, and adding it to the boot-up sequence with update-rc.d .  Since I don’t care about looking at the email I’ve routed the output to /dev/null.  But you could just as easily append it to a text file to read periodically.

sudo echo "python -m smtpd -n -c DebuggingServer localhost:25 > /dev/null 2>&1 &" > /etc/init.d/fake-smtp
sudo chmod +x /etc/init.d/fake-smtp
sudo update-rc.d fake-smtp defaults

You may get a message complaining about invalid header information.  But that’s not important as your background task will still start up on boot.  And even though it won’t shutdown properly through this script, the computer will be turning off anyways so that will close it.

And now my Rails test passes splendidly.  If you’d like to start the script without rebooting just type:

sudo /etc/init.d/fake-smtp start

If you want to write to a text file just change /dev/null to the path and file you want written to.  If you want it to append to the text file and not overwrite then change the preceding greater than symbol to two greater than symbols >>.

Summary

I’m quite happy that Python has included this debugging tool as it allows me a no hassle use as I don’t have to install anything or worry about any file clutter.

Please feel free to comment, share, subscribe to my RSS Feed, and follow me on twitter @6ftdan!

God Bless!
-Daniel P. Clark

Image by greg westfall via the Creative Commons Attribution 2.0 Generic License.

#linux#mail#python#rails#smtp#smtpd#testing#ubuntu

Comments

  1. grosser
    May 12, 2015 - 2:55 pm

    FYI You can use mailcrate gem to create a in-process smtp server.

  2. underpantsgnome
    May 12, 2015 - 2:59 pm

    Is this what you were looking for? http://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-configuration have a look at delivery_method

    • Daniel P. Clark
      May 12, 2015 - 3:13 pm

      Yeah, this is what I’d seen. But my test environment already has the delivery_method set to :test and I was still getting this error. Setting perform_deliveries to false may fix this error as it “can be turned off to help functional testing.”. I didn’t see that in any testing documentation though. Should be easy enough to do in config/environments/test.rb

      • underpantsgnome
        May 12, 2015 - 3:19 pm

        Strange, any possibility it’s being set someplace else? I’ve run in to that on some client apps, where they are setting one global config so no matter what you set for an environment it gets ignored.

        • Daniel P. Clark
          May 12, 2015 - 3:23 pm

          Perhaps so. It seems to be in an initializer.

          
          grep -R "delivery_method"
          config/initializers/mail.rb:ActionMailer::Base.delivery_method = :smtp
          config/environments/test.rb:  config.action_mailer.delivery_method = :test
          config/environments/production.rb:  config.action_mailer.delivery_method = :smtp
          
          • underpantsgnome
            May 12, 2015 - 3:28 pm

            That’ll do it. That mail initializer will run after your environment config. 🙂

Leave a Reply

Your email address will not be published / Required fields are marked *