- Notifications
You must be signed in to change notification settings - Fork20
SMTP mock server written on Golang. Mimic any 📤 SMTP server behavior for your test environment with fake SMTP server.
License
mocktools/go-smtp-mock
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
smtpmock
is lightweight configurable multithreaded fake SMTP server written in Go. It meets the minimum requirements specified byRFC 2821 &RFC 5321. Allows to mimic any SMTP server behavior for your test environment and even more 🚀
- Configurable multithreaded RFC compatible SMTP server
- Implements the minimum command set, responds to commands and adds a valid received header to messages as specified inRFC 2821 &RFC 5321
- Ability to configure behavior for each SMTP command
- Comes with default settings out of the box, configure only what you need
- Ability to override previous SMTP commands
- Fail fast scenario (ability to close client session for case when command was inconsistent or failed)
- Multiple receivers (ability to configure multiple
RCPT TO
commands receiving during one session) - Multiple message receiving (ability to configure multiple message receiving during one session)
- Mock-server activity logger
- Ability to do graceful/force shutdown of SMTP mock server
- No authentication support
- Zero runtime dependencies
- Ability to access to server messages
- Simple and intuitive DSL
- Ability to run server as binary with command line arguments
Golang 1.15+
Installsmtpmock
:
go get github.com/mocktools/go-smtp-mock/v2go install github.com/mocktools/go-smtp-mock/v2
Importsmtpmock
dependency into your code:
package mainimport smtpmock"github.com/mocktools/go-smtp-mock/v2"
You have to create your SMTP mock server usingsmtpmock.New()
andsmtpmock.ConfigurationAttr{}
to start interaction with it.
smtpmock
is SMTP server for test environment with configurable behavior. It comes with default settings out of the box. But you can override any default behavior if you need.
smtpmock.ConfigurationAttr{// Customizing server behavior// ---------------------------------------------------------------------// Host address where smtpmock will run, it's equal to "127.0.0.1" by defaultHostAddress:"[::]",// Port number on which the server will bind. If it not specified, it will be// assigned dynamically after server.Start() by defaultPortNumber:2525,// Enables/disables log to stdout. It's equal to false by defaultLogToStdout:true,// Enables/disables log server activity. It's equal to false by defaultLogServerActivity:true,// Ability to specify session timeout. It's equal to 30 seconds by defaultSessionTimeout:42,// Ability to specify graceful shutdown timeout. It's equal to 1 second by defaultShutdownTimeout:5,// Customizing SMTP command handlers behavior// ---------------------------------------------------------------------// Ability to configure fail fast scenario. It means that server will// close client session for case when command was inconsistent or failed.// It's equal to false by defaultIsCmdFailFast:true,// Ability to configure multiple RCPT TO command receiving during one session.// It means that server will handle and save all RCPT TO command request-response// pairs until receive successful response and next SMTP command has been passed.// Please note, by default will be saved only one, the last RCPT TO command// request-response pair. It's equal to false by defaultMultipleRcptto:true,// Ability to configure multiple message receiving during one session. It means that server// will create another message during current SMTP session in case when RSET// command has been used after successful commands chain: MAIL FROM, RCPT TO, DATA.// Please note, by default RSET command flushes current message in any case.// It's equal to false by defaultMultipleMessageReceiving:true,// Ability to specify blacklisted HELO domains. It's equal to empty []stringBlacklistedHeloDomains: []string{"example1.com","example2.com","localhost"},// Ability to specify blacklisted MAIL FROM emails. It's equal to empty []stringBlacklistedMailfromEmails: []string{"bot@olo.com","robot@molo.com"},// Ability to specify blacklisted RCPT TO emails. It's equal to empty []stringBlacklistedRcpttoEmails: []string{"blacklisted@olo.com","blacklisted@molo.com"},// Ability to specify not registered (non-existent) RCPT TO emails.// It's equal to empty []stringNotRegisteredEmails: []string{"nobody@olo.com","non-existent@email.com"},// Ability to specify HELO response delay in seconds. It runs immediately,// equals to 0 seconds by defaultResponseDelayHelo:2,// Ability to specify MAIL FROM response delay in seconds. It runs immediately,// equals to 0 seconds by defaultResponseDelayMailfrom:2,// Ability to specify RCPT TO response delay in seconds. It runs immediately,// equals to 0 seconds by defaultResponseDelayRcptto:2,// Ability to specify DATA response delay in seconds. It runs immediately,// equals to 0 seconds by defaultResponseDelayData:2,// Ability to specify message response delay in seconds. It runs immediately,// equals to 0 seconds by defaultResponseDelayMessage:2,// Ability to specify RSET response delay in seconds. It runs immediately,// equals to 0 seconds by defaultResponseDelayRset:2,// Ability to specify NOOP response delay in seconds. It runs immediately,// equals to 0 seconds by defaultResponseDelayNoop:2,// Ability to specify QUIT response delay in seconds. It runs immediately,// equals to 0 seconds by defaultResponseDelayQuit:2,// Ability to specify message body size limit. It's equal to 10485760 bytes (10MB) by defaultMsgSizeLimit:5,// Customizing SMTP command handler messages context// ---------------------------------------------------------------------// Custom server greeting message. Base on defaultGreetingMsg by defaultMsgGreeting:"msgGreeting",// Custom invalid command message. Based on defaultInvalidCmdMsg by defaultMsgInvalidCmd:"msgInvalidCmd",// Custom invalid command HELO sequence message.// Based on defaultInvalidCmdHeloSequenceMsg by defaultMsgInvalidCmdHeloSequence:"msgInvalidCmdHeloSequence",// Custom invalid command HELO argument message.// Based on defaultInvalidCmdHeloArgMsg by defaultMsgInvalidCmdHeloArg:"msgInvalidCmdHeloArg",// Custom HELO blacklisted domain message. Based on defaultQuitMsg by defaultMsgHeloBlacklistedDomain:"msgHeloBlacklistedDomain",// Custom HELO received message. Based on defaultReceivedMsg by defaultMsgHeloReceived:"msgHeloReceived",// Custom invalid command MAIL FROM sequence message.// Based on defaultInvalidCmdMailfromSequenceMsg by defaultMsgInvalidCmdMailfromSequence:"msgInvalidCmdMailfromSequence",// Custom invalid command MAIL FROM argument message.// Based on defaultInvalidCmdMailfromArgMsg by defaultMsgInvalidCmdMailfromArg:"msgInvalidCmdMailfromArg",// Custom MAIL FROM blacklisted email message. Based on defaultQuitMsg by defaultMsgMailfromBlacklistedEmail:"msgMailfromBlacklistedEmail",// Custom MAIL FROM received message. Based on defaultReceivedMsg by defaultMsgMailfromReceived:"msgMailfromReceived",// Custom invalid command RCPT TO sequence message.// Based on defaultInvalidCmdRcpttoSequenceMsg by defaultMsgInvalidCmdRcpttoSequence:"msgInvalidCmdRcpttoSequence",// Custom invalid command RCPT TO argument message.// Based on defaultInvalidCmdRcpttoArgMsg by defaultMsgInvalidCmdRcpttoArg:"msgInvalidCmdRcpttoArg",// Custom RCPT TO not registered email message.// Based on defaultNotRegisteredRcpttoEmailMsg by defaultMsgRcpttoNotRegisteredEmail:"msgRcpttoNotRegisteredEmail",// Custom RCPT TO blacklisted email message. Based on defaultQuitMsg by defaultMsgRcpttoBlacklistedEmail:"msgRcpttoBlacklistedEmail",// Custom RCPT TO received message. Based on defaultReceivedMsg by defaultMsgRcpttoReceived:"msgRcpttoReceived",// Custom invalid command DATA sequence message.// Based on defaultInvalidCmdDataSequenceMsg by defaultMsgInvalidCmdDataSequence:"msgInvalidCmdDataSequence",// Custom DATA received message. Based on defaultReadyForReceiveMsg by defaultMsgDataReceived:"msgDataReceived",// Custom size is too big message. Based on defaultMsgSizeIsTooBigMsg by defaultMsgMsgSizeIsTooBig:"msgMsgSizeIsTooBig",// Custom received message body message. Based on defaultReceivedMsg by defaultMsgMsgReceived:"msgMsgReceived",// Custom invalid command RSET sequence message.// Based on defaultInvalidCmdHeloSequenceMsg by defaultMsgInvalidCmdRsetSequence:"msgInvalidCmdRsetSequence",// Custom invalid command RSET message. Based on defaultInvalidCmdMsg by defaultMsgInvalidCmdRsetArg:"msgInvalidCmdRsetArg",// Custom RSET received message. Based on defaultOkMsg by defaultMsgRsetReceived:"msgRsetReceived",// Custom NOOP received message. Based on defaultOkMsg by defaultMsgNoopReceived:"msgNoopReceived",// Custom quit command message. Based on defaultQuitMsg by defaultMsgQuitCmd:"msgQuitCmd",}
package mainimport ("fmt""net""net/smtp" smtpmock"github.com/mocktools/go-smtp-mock/v2")funcmain() {// You can pass empty smtpmock.ConfigurationAttr{}. It means that smtpmock will use default settingsserver:=smtpmock.New(smtpmock.ConfigurationAttr{LogToStdout:true,LogServerActivity:true, })// To start server use Start() methodiferr:=server.Start();err!=nil {fmt.Println(err) }// Server's port will be assigned dynamically after server.Start()// for case when portNumber wasn't specifiedhostAddress,portNumber:="127.0.0.1",server.PortNumber()// Possible SMTP-client stuff for iteration with mock serveraddress:=fmt.Sprintf("%s:%d",hostAddress,portNumber)timeout:=time.Duration(2)*time.Secondconnection,_:=net.DialTimeout("tcp",address,timeout)client,_:=smtp.NewClient(connection,hostAddress)client.Hello("example.com")client.Quit()client.Close()// Each result of SMTP session will be saved as message.// To get access for server messages copies use Messages() methodserver.Messages()// To get access for server messages copies and purge it on server after// use MessagesAndPurge() methodserver.MessagesAndPurge()// In case with flaky test environment you can wait for the specified number// of messages to arrive or until timeout is reached use WaitForMessages() methodserver.WaitForMessages(42,1*time.Millisecond)// In case with flaky test environment you can wait for the specified number// of messages to arrive or until timeout is reached and purge it on server// after use WaitForMessagesAndPurge() methodserver.WaitForMessagesAndPurge(42,1*time.Millisecond)// To stop the server use Stop() method. Please note, smtpmock uses graceful shutdown.// It means that smtpmock will end all sessions after client responses or by session// timeouts immediately.iferr:=server.Stop();err!=nil {fmt.Println(err) }}
Code from example above will produce next output to stdout:
INFO: 2021/11/30 22:07:30.554827 SMTP mock server started on port: 2525INFO: 2021/11/30 22:07:30.554961 SMTP session startedINFO: 2021/11/30 22:07:30.554998 SMTP response: 220 WelcomeINFO: 2021/11/30 22:07:30.555059 SMTP request: EHLO example.comINFO: 2021/11/30 22:07:30.555648 SMTP response: 250 ReceivedINFO: 2021/11/30 22:07:30.555686 SMTP request: QUITINFO: 2021/11/30 22:07:30.555722 SMTP response: 221 Closing connectionINFO: 2021/11/30 22:07:30.555732 SMTP session finishedWARNING: 2021/11/30 22:07:30.555801 SMTP mock server is in the shutdown mode and won't accept new connectionsINFO: 2021/11/30 22:07:30.555808 SMTP mock server was stopped successfully
In Ruby ecosystemsmtpmock
is available assmtp_mock
gem. It's flexible Ruby wrapper oversmtpmock
binary.
First, you should installsmtp_mock
gem andsmtpmock
as system dependency:
gem install smtp_mockbundleexec smtp_mock -i~
Now, you can create and interact with yoursmtpmock
instance natively from Ruby ecosystem. It comes with default settings out of the box. Configure only what you need, for example:
require'smtp_mock'# List of all available server options:# https://github.com/mocktools/ruby-smtp-mock#available-server-optionssmtp_mock_server=SmtpMock.start_server(not_registered_emails:%w[user@olo.comuser@molo.com])# returns current smtp mock server portsmtp_mock_server.port# => 55640# interface for force shutdown current smtp mock serversmtp_mock_server.stop!# => true
You can usesmtpmock
as binary. Just download the pre-compiled binary from thereleases page and copy them to the desired location. For start server run command with needed arguments. You can use our bash script for automation this process like in the example below:
curl -sL https://raw.githubusercontent.com/mocktools/go-smtp-mock/master/script/download.sh| bash./smtpmock -port=2525 -log
smtpmock
configuration is available as command line arguments specified in the list below:
Flag description | Example of usage |
---|---|
-host - host address where smtpmock will run. It's equal to127.0.0.1 by default | -host=localhost |
-port - server port number. If not specified it will be assigned dynamically | -port=2525 |
-log - enables log server activity. Disabled by default | -log |
-sessionTimeout - session timeout in seconds. It's equal to 30 seconds by default | -sessionTimeout=60 |
-shutdownTimeout - graceful shutdown timeout in seconds. It's equal to 1 second by default | -shutdownTimeout=5 |
-failFast - enables fail fast scenario. Disabled by default | -failFast |
-multipleRcptto - enables multipleRCPT TO receiving scenario. Disabled by default | -multipleRcptto |
-multipleMessageReceiving - enables multiple message receiving scenario. Disabled by default | -multipleMessageReceiving |
-blacklistedHeloDomains - blacklistedHELO domains, separated by commas | -blacklistedHeloDomains="example1.com,example2.com" |
-blacklistedMailfromEmails - blacklistedMAIL FROM emails, separated by commas | -blacklistedMailfromEmails="a@example1.com,b@example2.com" |
-blacklistedRcpttoEmails - blacklistedRCPT TO emails, separated by commas | -blacklistedRcpttoEmails="a@example1.com,b@example2.com" |
-notRegisteredEmails - not registered (non-existent)RCPT TO emails, separated by commas | -notRegisteredEmails="a@example1.com,b@example2.com" |
-responseDelayHelo -HELO response delay in seconds. It's equal to 0 seconds by default | -responseDelayHelo=2 |
-responseDelayMailfrom -MAIL FROM response delay in seconds. It's equal to 0 seconds by default | -responseDelayMailfrom=2 |
-responseDelayRcptto -RCPT TO response delay in seconds. It's equal to 0 seconds by default | -responseDelayRcptto=2 |
-responseDelayData -DATA response delay in seconds. It's equal to 0 seconds by default | -responseDelayData=2 |
-responseDelayMessage - Message response delay in seconds. It's equal to 0 seconds by default | -responseDelayMessage=2 |
-responseDelayRset -RSET response delay in seconds. It's equal to 0 seconds by default | -responseDelayRset=2 |
-responseDelayNoop -NOOP response delay in seconds. It's equal to 0 seconds by default | -responseDelayNoop=2 |
-responseDelayQuit -QUIT response delay in seconds. It's equal to 0 seconds by default | -responseDelayQuit=2 |
-msgSizeLimit - message body size limit in bytes. It's equal to10485760 bytes | -msgSizeLimit=42 |
-msgGreeting - custom server greeting message | -msgGreeting="Greeting message" |
-msgInvalidCmd - custom invalid command message | -msgInvalidCmd="Invalid command message" |
-msgInvalidCmdHeloSequence - custom invalid commandHELO sequence message | -msgInvalidCmdHeloSequence="Invalid command HELO sequence message" |
-msgInvalidCmdHeloArg - custom invalid commandHELO argument message | -msgInvalidCmdHeloArg="Invalid command HELO argument message" |
-msgHeloBlacklistedDomain - customHELO blacklisted domain message | -msgHeloBlacklistedDomain="Blacklisted domain message" |
-msgHeloReceived - customHELO received message | -msgHeloReceived="HELO received message" |
-msgInvalidCmdMailfromSequence - custom invalid commandMAIL FROM sequence message | -msgInvalidCmdMailfromSequence="Invalid command MAIL FROM sequence message" |
-msgInvalidCmdMailfromArg - custom invalid commandMAIL FROM argument message | -msgInvalidCmdMailfromArg="Invalid command MAIL FROM argument message" |
-msgMailfromBlacklistedEmail - customMAIL FROM blacklisted email message | -msgMailfromBlacklistedEmail="Blacklisted email message" |
-msgMailfromReceived - customMAIL FROM received message | -msgMailfromReceived="MAIL FROM received message" |
-msgInvalidCmdRcpttoSequence - custom invalid commandRCPT TO sequence message | -msgInvalidCmdRcpttoSequence="Invalid command RCPT TO sequence message" |
-msgInvalidCmdRcpttoArg - custom invalid commandRCPT TO argument message | -msgInvalidCmdRcpttoArg="Invalid command RCPT TO argument message" |
-msgRcpttoNotRegisteredEmail - customRCPT TO not registered email message | -msgRcpttoNotRegisteredEmail="Not registered email message" |
-msgRcpttoBlacklistedEmail - customRCPT TO blacklisted email message | -msgRcpttoBlacklistedEmail="Blacklisted email message" |
-msgRcpttoReceived - customRCPT TO received message | -msgRcpttoReceived="RCPT TO received message" |
-msgInvalidCmdDataSequence - custom invalid commandDATA sequence message | -msgInvalidCmdDataSequence="Invalid command DATA sequence message" |
-msgDataReceived - customDATA received message | -msgDataReceived="DATA received message" |
-msgMsgSizeIsTooBig - custom size is too big message | -msgMsgSizeIsTooBig="Message size is too big" |
-msgMsgReceived - custom received message body message | -msgMsgReceived="Message has been received" |
-msgInvalidCmdRsetSequence - custom invalid commandRSET sequence message | -msgInvalidCmdRsetSequence="Invalid command RSET sequence message" |
-msgInvalidCmdRsetArg - custom invalid commandRSET message | -msgInvalidCmdRsetArg="Invalid command RSET message" |
-msgRsetReceived - customRSET received message | -msgRsetReceived="RSET received message" |
-msgNoopReceived - customNOOP received message | -msgNoopReceived="NOOP received message" |
-msgQuitCmd - customQUIT command message | -msgQuitCmd="Quit command message" |
Available not configurationsmtpmock
options:
Flag description | Example of usage |
---|---|
-v - Just prints currentsmtpmock binary build data (version, commit, datetime). Doesn't run the server. | -v |
smtpmock
accepts 3 shutdown signals:SIGINT
,SIGQUIT
,SIGTERM
.
id | Command | Sequenceable | Available args | Example of usage |
---|---|---|---|---|
1 | HELO | no | domain name ,localhost ,ip address ,[ip address] | HELO example.com |
1 | EHLO | no | domain name ,localhost ,ip address ,[ip address] | EHLO example.com |
2 | MAIL FROM | can be used after command with id1 and greater | email address ,<email address> ,localhost email address ,<localhost email address> | MAIL FROM: user@domain.com |
3 | RCPT TO | can be used after command with id2 and greater | email address ,<email address> ,localhost email address ,<localhost email address> | RCPT TO: user@domain.com |
4 | DATA | can be used after command with id3 | - | DATA |
5 | RSET | can be used after command with id1 and greater | - | RSET |
6 | NOOP | no | - | NOOP |
7 | QUIT | no | - | QUIT |
Please note in case when same command used more the one time during same session all saved data upper this command will be erased.
Bug reports and pull requests are welcome on GitHub athttps://github.com/mocktools/go-smtp-mock. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to theContributor Covenant code of conduct. Please check theopen tickets. Be sure to follow Contributor Code of Conduct below and ourContributing Guidelines.
This golang package is available as open source under the terms of theMIT License.
Everyone interacting in thesmtpmock
project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow thecode of conduct.
- The Contributors for code and awesome suggestions
- The Stargazers for showing their support
smtpmock
usesSemantic Versioning 2.0.0
About
SMTP mock server written on Golang. Mimic any 📤 SMTP server behavior for your test environment with fake SMTP server.