golang轻量级可配置多线程模拟SMTP服务器插件smtpmock的使用

Golang轻量级可配置多线程模拟SMTP服务器插件smtpmock的使用

smtpmock是一个用Go编写的轻量级可配置多线程模拟SMTP服务器,它符合RFC 2821和RFC 5321规范的最小要求,可以模拟任何SMTP服务器行为用于测试环境。

主要特性

  • 可配置的多线程RFC兼容SMTP服务器
  • 实现最小命令集,根据RFC规范响应命令并为消息添加有效的接收头
  • 能够为每个SMTP命令配置行为
  • 开箱即用的默认设置,只需配置你需要的部分
  • 能够覆盖之前的SMTP命令
  • 快速失败场景(当命令不一致或失败时关闭客户端会话)
  • 多接收者支持(在一个会话中配置多个RCPT TO命令接收)
  • 多消息接收支持
  • 服务器活动日志记录
  • 支持优雅/强制关闭SMTP模拟服务器
  • 零运行时依赖

安装

安装smtpmock:

go get github.com/mocktools/go-smtp-mock/v2
go install github.com/mocktools/go-smtp-mock/v2

在代码中导入smtpmock依赖:

package main

import smtpmock "github.com/mocktools/go-smtp-mock/v2"

使用示例

在Golang生态系统中使用

配置服务器

server := smtpmock.New(smtpmock.ConfigurationAttr{
    // 服务器行为配置
    HostAddress:       "[::]",  // 服务器运行的主机地址,默认为"127.0.0.1"
    PortNumber:        2525,    // 服务器绑定的端口号,未指定时会动态分配
    LogToStdout:       true,    // 启用/禁用标准输出日志,默认为false
    LogServerActivity: true,    // 启用/禁用服务器活动日志,默认为false
    SessionTimeout:    42,      // 会话超时时间,默认为30秒
    ShutdownTimeout:   5,       // 优雅关闭超时时间,默认为1秒

    // SMTP命令处理行为配置
    IsCmdFailFast:            true,  // 启用快速失败场景,默认为false
    MultipleRcptto:           true,  // 启用多RCPT TO接收,默认为false
    MultipleMessageReceiving: true,  // 启用多消息接收,默认为false
    
    // 黑名单和响应延迟配置
    BlacklistedHeloDomains:    []string{"example1.com", "example2.com"},
    BlacklistedMailfromEmails: []string{"bot@olo.com", "robot@molo.com"},
    ResponseDelayHelo:         2,    // HELO响应延迟秒数
    ResponseDelayMailfrom:     2,    // MAIL FROM响应延迟秒数
    
    // 自定义消息
    MsgGreeting:      "msgGreeting",      // 自定义服务器欢迎消息
    MsgInvalidCmd:    "msgInvalidCmd",    // 自定义无效命令消息
    MsgHeloReceived:  "msgHeloReceived",  // 自定义HELO接收消息
})

服务器操作示例

package main

import (
    "fmt"
    "net"
    "net/smtp"
    "time"

    smtpmock "github.com/mocktools/go-smtp-mock/v2"
)

func main() {
    // 创建服务器实例
    server := smtpmock.New(smtpmock.ConfigurationAttr{
        LogToStdout:       true,
        LogServerActivity: true,
    })

    // 启动服务器
    if err := server.Start(); err != nil {
        fmt.Println(err)
    }

    // 获取服务器地址和端口
    hostAddress, portNumber := "127.0.0.1", server.PortNumber()

    // 创建SMTP客户端连接
    address := fmt.Sprintf("%s:%d", hostAddress, portNumber)
    timeout := time.Duration(2) * time.Second

    connection, _ := net.DialTimeout("tcp", address, timeout)
    client, _ := smtp.NewClient(connection, hostAddress)
    client.Hello("example.com")
    client.Quit()
    client.Close()

    // 获取服务器消息
    messages := server.Messages()
    fmt.Printf("Received messages: %+v\n", messages)

    // 停止服务器
    if err := server.Stop(); err != nil {
        fmt.Println(err)
    }
}

使用自定义日志器

package main

import (
    "bytes"
    "fmt"

    smtpmock "github.com/mocktools/go-smtp-mock/v2"
)

// 自定义日志器实现
type customLogger struct {
    out *bytes.Buffer
    err *bytes.Buffer
}

func (logger *customLogger) InfoActivity(message string) {
    logger.out.WriteString(message)
}

func (logger *customLogger) Info(message string) {
    logger.out.WriteString(message)
}

func (logger *customLogger) Warning(message string) {
    logger.out.WriteString(message)
}

func (logger *customLogger) Error(message string) {
    logger.err.WriteString(message)
}

func main() {
    server := smtpmock.New(smtpmock.ConfigurationAttr{
        LogToStdout:       true,
        LogServerActivity: true,
    })

    // 设置自定义日志器
    outBuf := &bytes.Buffer{}
    errBuf := &bytes.Buffer{}
    server.WithLogger(&customLogger{
        out: outBuf,
        err: errBuf,
    })

    // 启动和停止服务器
    if err := server.Start(); err != nil {
        fmt.Println(err)
    }
    
    if err := server.Stop(); err != nil {
        fmt.Println(err)
    }
}

在Ruby生态系统中使用

在Ruby生态系统中,smtpmock可以作为smtp_mock gem使用,它是smtpmock二进制文件的灵活Ruby包装器。

安装和使用示例:

gem install smtp_mock
bundle exec smtp_mock -i ~

Ruby代码示例:

require 'smtp_mock'

# 启动服务器并配置
smtp_mock_server = SmtpMock.start_server(not_registered_emails: %w[user@olo.com user@molo.com])

# 获取服务器端口
smtp_mock_server.port # => 55640

# 停止服务器
smtp_mock_server.stop! # => true

在任何生态系统中使用

你可以将smtpmock作为二进制文件使用。下载预编译的二进制文件后,使用以下命令启动服务器:

curl -sL https://raw.githubusercontent.com/mocktools/go-smtp-mock/master/script/download.sh | bash
./smtpmock -port=2525 -log

已实现的SMTP命令

id 命令 可序列化 可用参数 使用示例
1 HELO 域名, localhost, IP地址 HELO example.com
1 EHLO 域名, localhost, IP地址 EHLO example.com
2 MAIL FROM 邮箱地址, <邮箱地址> MAIL FROM: user@domain.com
3 RCPT TO 邮箱地址, <邮箱地址> RCPT TO: user@domain.com
4 DATA - DATA
5 RSET - RSET
6 NOOP - NOOP
7 QUIT - QUIT

贡献

欢迎在GitHub上提交错误报告和拉取请求。请遵循贡献者行为准则和我们的贡献指南。

许可证

此Go包是根据MIT许可证条款提供的开源软件。


更多关于golang轻量级可配置多线程模拟SMTP服务器插件smtpmock的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang轻量级可配置多线程模拟SMTP服务器插件smtpmock的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang轻量级可配置多线程SMTP模拟服务器 - smtpmock

smtpmock是一个轻量级的Golang库,用于模拟SMTP服务器行为,非常适合测试电子邮件发送功能的场景。下面我将详细介绍其使用方法和示例代码。

主要特性

  • 轻量级且易于配置
  • 支持多线程处理
  • 可模拟各种SMTP响应
  • 支持验证接收的邮件内容
  • 提供丰富的钩子函数

安装

go get github.com/mocktools/go-smtp-mock/v2

基础使用示例

package main

import (
	"fmt"
	"log"
	"time"

	"github.com/mocktools/go-smtp-mock/v2"
)

func main() {
	// 创建SMTP模拟服务器
	server := smtpmock.New(smtpmock.ConfigurationAttr{
		HostAddress:       "127.0.0.1",
		PortNumber:        2525,
		LogToStdout:       true,
		LogServerActivity: true,
	})

	// 启动服务器
	if err := server.Start(); err != nil {
		log.Fatal(err)
	}

	// 模拟邮件发送测试代码可以在这里运行
	fmt.Println("SMTP Mock Server is running on 127.0.0.1:2525")

	// 保持服务器运行
	time.Sleep(5 * time.Minute)

	// 停止服务器
	if err := server.Stop(); err != nil {
		log.Fatal(err)
	}
}

高级配置示例

package main

import (
	"fmt"
	"log"
	"time"

	"github.com/mocktools/go-smtp-mock/v2"
)

func main() {
	// 创建具有详细配置的SMTP模拟服务器
	server := smtpmock.New(smtpmock.ConfigurationAttr{
		HostAddress:           "127.0.0.1",
		PortNumber:            2525,
		LogToStdout:           true,
		LogServerActivity:     true,
		MultipleMessageReceiving: true, // 允许接收多条消息
		ResponseDelay:         1,       // 1秒延迟响应
		SessionTimeout:        30,      // 30秒会话超时
		BlacklistedHeloDomains: []string{"spam.com"}, // 黑名单域名
		BlacklistedMailfromEmails: []string{"spammer@example.com"}, // 黑名单发件人
		BlacklistedRcpttoEmails: []string{"victim@example.com"}, // 黑名单收件人
	})

	// 添加消息接收钩子
	server.AddOnNewMessageHook(func(message *smtpmock.Message) {
		fmt.Printf("Received new message from: %s\n", message.Mailfrom)
		fmt.Printf("Subject: %s\n", message.MsgHeaders["Subject"])
		fmt.Printf("Body: %s\n", message.MsgData)
	})

	// 启动服务器
	if err := server.Start(); err != nil {
		log.Fatal(err)
	}

	fmt.Println("Advanced SMTP Mock Server is running on 127.0.0.1:2525")

	// 保持服务器运行
	time.Sleep(10 * time.Minute)

	// 停止服务器
	if err := server.Stop(); err != nil {
		log.Fatal(err)
	}
}

测试用例示例

package main_test

import (
	"net/smtp"
	"testing"
	"time"

	"github.com/mocktools/go-smtp-mock/v2"
	"github.com/stretchr/testify/assert"
)

func TestSMTPSending(t *testing.T) {
	// 创建测试服务器
	server := smtpmock.New(smtpmock.ConfigurationAttr{
		HostAddress:       "127.0.0.1",
		PortNumber:        5870,
		LogToStdout:       false,
		LogServerActivity: false,
	})

	// 启动服务器
	if err := server.Start(); err != nil {
		t.Fatal(err)
	}
	defer server.Stop()

	// 模拟发送邮件
	client, err := smtp.Dial("127.0.0.1:5870")
	assert.NoError(t, err)

	err = client.Mail("sender@example.com")
	assert.NoError(t, err)

	err = client.Rcpt("recipient@example.com")
	assert.NoError(t, err)

	wc, err := client.Data()
	assert.NoError(t, err)

	_, err = wc.Write([]byte("Subject: Test\n\nHello World"))
	assert.NoError(t, err)

	err = wc.Close()
	assert.NoError(t, err)

	err = client.Quit()
	assert.NoError(t, err)

	// 等待服务器处理
	time.Sleep(100 * time.Millisecond)

	// 验证接收到的消息
	messages := server.Messages()
	assert.Equal(t, 1, len(messages))

	msg := messages[0]
	assert.Equal(t, "sender@example.com", msg.Mailfrom)
	assert.Equal(t, []string{"recipient@example.com"}, msg.Rcptto)
	assert.Contains(t, msg.MsgData, "Hello World")
}

自定义响应

package main

import (
	"fmt"
	"log"

	"github.com/mocktools/go-smtp-mock/v2"
)

func main() {
	server := smtpmock.New(smtpmock.ConfigurationAttr{
		HostAddress: "127.0.0.1",
		PortNumber:  2525,
	})

	// 自定义EHLO响应
	server.SetEhloResponse("example.com", "250-mock-server.example.com\n250-PIPELINING\n250-SIZE 10240000\n250-ENHANCEDSTATUSCODES\n250-8BITMIME\n250-DSN\n250 SMTPUTF8")

	// 自定义MAIL FROM响应
	server.SetMailfromResponse("250 2.1.0 Sender OK")

	// 自定义RCPT TO响应
	server.SetRcpttoResponse("250 2.1.5 Recipient OK")

	// 自定义DATA响应
	server.SetDataResponse("354 End data with <CR><LF>.<CR><LF>")

	// 自定义消息接收后的响应
	server.SetDataReceivedResponse("250 2.0.0 OK: queued as ABC123")

	if err := server.Start(); err != nil {
		log.Fatal(err)
	}

	fmt.Println("Customized SMTP Mock Server is running on 127.0.0.1:2525")

	// 保持服务器运行
	select {}
}

总结

smtpmock是一个功能强大且灵活的SMTP模拟服务器,特别适合以下场景:

  1. 单元测试中模拟邮件发送
  2. 开发环境替代真实SMTP服务器
  3. 测试邮件发送失败的各种情况
  4. 验证邮件内容和格式

通过上述示例代码,您可以快速集成smtpmock到您的测试流程中,它提供了丰富的配置选项和钩子函数,可以满足大多数SMTP测试需求。

回到顶部