Home

Awesome

Ruby SmtpMock - mimic any 📤 SMTP server behavior for your test environment with fake SMTP server

Maintainability Test Coverage CircleCI Gem Version Downloads In Awesome Ruby GitHub Contributor Covenant

💎 Ruby SMTP mock - flexible Ruby wrapper over smtpmock. Mimic any 📤 SMTP server behavior for your test environment and even more.

Table of Contents

Features

Requirements

Ruby MRI 2.5.0+

Installation

Add this line to your application's Gemfile:

group :development, :test do
  gem 'smtp_mock', require: false
end

And then execute:

bundle

Or install it yourself as:

gem install smtp_mock

Then install smtpmock as system dependency:

bundle exec smtp_mock -i ~

Usage

Dependency manager

This gem includes easy system dependency manager. Run bundle exec smtp_mock with options for manage smtpmock system dependency.

Available flags

FlagDescriptionExample of usage
-s, --sudoRun command as sudobundle exec smtp_mock -s -i ~
-i, --install=PATHInstall smtpmock to the existing pathbundle exec smtp_mock -i ~/existent_dir
-u, --uninstallUninstall smtpmockbundle exec smtp_mock -u
-g, --upgradeUpgrade to latest version of smtpmockbundle exec smtp_mock -g
-v, --versionPrints current version of smtpmockbundle exec smtp_mock -v
-h, --helpPrints helpbundle exec smtp_mock -h

DSL

Available server options

Example of usage kwargDescription
host: '0.0.0.0'Host address where smtpmock will run. It's equal to 127.0.0.1 by default
port: 2525Server port number. If not specified it will be assigned dynamically
log: trueEnables log server activity. Disabled by default
session_timeout: 60Session timeout in seconds. It's equal to 30 seconds by default
shutdown_timeout: 5Graceful shutdown timeout in seconds. It's equal to 1 second by default
fail_fast: trueEnables fail fast scenario. Disabled by default
multiple_rcptto: trueEnables multiple RCPT TO receiving scenario. Disabled by default
multiple_message_receiving: trueEnables multiple message receiving scenario. Disabled by default
blacklisted_helo_domains: %w[a.com b.com]Blacklisted HELO domains
blacklisted_mailfrom_emails: %w[a@a.com b@b.com]Blacklisted MAIL FROM emails
blacklisted_rcptto_emails: %w[c@c.com d@d.com]blacklisted RCPT TO emails
not_registered_emails: %w[e@e.com f@f.com]Not registered (non-existent) RCPT TO emails
response_delay_helo: 2HELO response delay in seconds. It's equal to 0 seconds by default
response_delay_mailfrom: 2MAIL FROM response delay in seconds. It's equal to 0 seconds by default
response_delay_rcptto: 2RCPT TO response delay in seconds. It's equal to 0 seconds by default
response_delay_data: 2DATA response delay in seconds. It's equal to 0 seconds by default
response_delay_message: 2Message response delay in seconds. It's equal to 0 seconds by default
response_delay_rset: 2RSET response delay in seconds. It's equal to 0 seconds by default
response_delay_quit: 2QUIT response delay in seconds. It's equal to 0 seconds by default
msg_size_limit: 42Message body size limit in bytes. It's equal to 10485760 bytes by default
msg_greeting: 'Greeting message'Custom server greeting message
msg_invalid_cmd: 'Invalid command message'Custom invalid command message
msg_invalid_cmd_helo_sequence: 'Invalid command HELO sequence message'Custom invalid command HELO sequence message
msg_invalid_cmd_helo_arg: 'Invalid command HELO argument message'Custom invalid command HELO argument message
msg_helo_blacklisted_domain: 'Blacklisted domain message'Custom HELO blacklisted domain message
msg_helo_received: 'HELO received message'Custom HELO received message
msg_invalid_cmd_mailfrom_sequence: 'Invalid command MAIL FROM sequence message'Custom invalid command MAIL FROM sequence message
msg_invalid_cmd_mailfrom_arg: 'Invalid command MAIL FROM argument message'Custom invalid command MAIL FROM argument message
msg_mailfrom_blacklisted_email: 'Blacklisted email message'Custom MAIL FROM blacklisted email message
msg_mailfrom_received: 'MAIL FROM received message'Custom MAIL FROM received message
msg_invalid_cmd_rcptto_sequence: 'Invalid command RCPT TO sequence message'Custom invalid command RCPT TO sequence message
msg_invalid_cmd_rcptto_arg: 'Invalid command RCPT TO argument message'Custom invalid command RCPT TO argument message
msg_rcptto_not_registered_email: 'Not registered email message'Custom RCPT TO not registered email message
msg_rcptto_blacklisted_email: 'Blacklisted email message'Custom RCPT TO blacklisted email message
msg_rcptto_received: 'RCPT TO received message'Custom RCPT TO received message
msg_invalid_cmd_data_sequence: 'Invalid command DATA sequence message'Custom invalid command DATA sequence message
msg_data_received: 'DATA received message'Custom DATA received message
msg_msg_size_is_too_big: 'Message size is too big'Custom size is too big message
msg_invalid_cmd_rset_sequence: 'Invalid command RSET sequence message'Custom invalid command RSET sequence message
msg_invalid_cmd_rset_arg: 'Invalid command RSET argument message'Custom invalid command RSET argument message
msg_rset_received: 'RSET received message'Custom RSET received message
msg_quit_cmd: 'Quit command message'Custom quit command message

Example of usage

# Public SmtpMock interface
# Without kwargs creates SMTP mock server with default behavior.
# A free port for server will be randomly assigned in the range
# from 49152 to 65535. Returns current smtp mock server instance
smtp_mock_server = SmtpMock.start_server(not_registered_emails: %w[user@example.com]) # => SmtpMock::Server instance

# returns current smtp mock server port
smtp_mock_server.port # => 55640

# returns current smtp mock server process identification number (PID)
smtp_mock_server.pid # => 38195

# returns current smtp mock server version
smtp_mock_server.version # => '1.5.2'

# interface for graceful shutdown current smtp mock server
smtp_mock_server.stop # => true

# interface for force shutdown current smtp mock server
smtp_mock_server.stop! # => true

# interface to check state of current smtp mock server
# returns true if server is running, otherwise returns false
smtp_mock_server.active? # => true

# returns list of running smtp mock servers
SmtpMock.running_servers # => [SmtpMock::Server instance]

# interface to stop all running smtp mock servers
SmtpMock.stop_running_servers! # => true

RSpec integration

Require this either in your Gemfile or in RSpec's support scripts. So either:

# Gemfile

group :test do
  gem 'rspec'
  gem 'smtp_mock', require: 'smtp_mock/test_framework/rspec'
end

or

# spec/support/config/smtp_mock.rb

require 'smtp_mock/test_framework/rspec'

SmtpMock RSpec helper

Just add SmtpMock::TestFramework::RSpec::Helper if you wanna use shortcut smtp_mock_server for SmtpMock server instance inside of your RSpec.describe blocks:

# spec/support/config/smtp_mock.rb

RSpec.configure do |config|
  config.include SmtpMock::TestFramework::RSpec::Helper
end
# your awesome smtp_client_spec.rb

RSpec.describe SmtpClient do
  subject(:smtp_response) do
    described_class.call(
      host: 'localhost',
      port: smtp_mock_server.port,
      mailfrom: mailfrom,
      rcptto: rcptto,
      message: message
    )
  end

  let(:mailfrom) { 'sender@example.com' }
  let(:rcptto) { 'receiver@example.com' }
  let(:message) { 'Email message context' }
  let(:expected_response_message) { '250 Custom successful response' }

  before { smtp_mock_server(msg_msg_received: expected_response_message) }

  it do
    expect(smtp_response).to be_success
    expect(smtp_response).to have_status(expected_response_status)
    expect(smtp_response).to have_message_context(expected_response_message)
  end
end

SmtpMock RSpec interface

If you won't use SmtpMock::TestFramework::RSpec::Helper you can use SmtpMock::TestFramework::RSpec::Interface directly instead:

SmtpMock::TestFramework::RSpec::Interface.start_server  # creates and runs SmtpMock server instance
SmtpMock::TestFramework::RSpec::Interface.stop_server!  # stops and clears current SmtpMock server instance
SmtpMock::TestFramework::RSpec::Interface.clear_server! # clears current SmtpMock server instance

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/mocktools/ruby-smtp-mock. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct. Please check the open tickets. Be sure to follow Contributor Code of Conduct below and our Contributing Guidelines.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the SmtpMock project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

Credits

Versioning

SmtpMock uses Semantic Versioning 2.0.0