golang实现DKIM电子邮件签名与验证插件库go-dkim的使用

golang实现DKIM电子邮件签名与验证插件库go-dkim的使用

go-dkim简介

go-dkim是一个用于Golang的DKIM(DomainKeys Identified Mail)包,可以实现电子邮件的签名和验证功能。

安装

go get github.com/toorop/go-dkim

注意:需要使用Go 1.4.2-master或1.4.3版本。

签名电子邮件

以下是一个完整的示例,展示如何使用go-dkim对电子邮件进行签名:

import (
	dkim "github.com/toorop/go-dkim"
)

func main(){
	// email是要签名的邮件内容(字节切片)
	// privateKey是私钥(PEM编码的字节切片)
	options := dkim.NewSigOptions()
	options.PrivateKey = privateKey
	options.Domain = "mydomain.tld"  // 你的域名
	options.Selector = "myselector"  // DKIM选择器
	options.SignatureExpireIn = 3600 // 签名过期时间(秒)
	options.BodyLength = 50          // 签名包含的邮件体长度
	options.Headers = []string{"from", "date", "mime-version", "received", "received"} // 要签名的邮件头
	options.AddSignatureTimestamp = true  // 添加签名时间戳
	options.Canonicalization = "relaxed/relaxed" // 规范化方法
	err := dkim.Sign(&email, options)
	// 处理错误...
	
	// 现在'email'已经被签名了!
}

验证签名

以下示例展示如何验证带有DKIM签名的电子邮件:

import (
	dkim "github.com/toorop/go-dkim"
)

func main(){
	// email是要验证的邮件内容(字节切片)
	status, err := dkim.Verify(&email)
	// 处理status和err(参见godoc了解status含义)
}

待办事项

  • 处理z标签(用于诊断用途的复制头字段)

这个库提供了简单易用的接口来实现电子邮件的DKIM签名和验证功能,可以帮助开发者确保邮件的真实性和完整性。


更多关于golang实现DKIM电子邮件签名与验证插件库go-dkim的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现DKIM电子邮件签名与验证插件库go-dkim的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用go-dkim实现DKIM电子邮件签名与验证

DKIM(DomainKeys Identified Mail)是一种电子邮件验证技术,允许接收方验证邮件确实来自声称的发件人域。下面我将介绍如何使用go-dkim库在Golang中实现DKIM签名和验证。

安装go-dkim

首先安装go-dkim库:

go get github.com/emersion/go-dkim

DKIM签名实现

以下是一个完整的DKIM签名示例:

package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net/mail"
	"os"
	"strings"
	"time"

	"github.com/emersion/go-dkim"
	"github.com/emersion/go-message/mail"
)

func main() {
	// 示例邮件内容
	rawEmail := `From: sender@example.com
To: recipient@example.com
Subject: Test DKIM Signed Email
Date: Mon, 23 Jun 2023 10:00:00 +0800
Message-ID: <123456789@example.com>
MIME-Version: 1.0
Content-Type: text/plain; charset="UTF-8"

This is a test email with DKIM signature.`

	// 解析邮件
	msg, err := mail.ReadMessage(strings.NewReader(rawEmail))
	if err != nil {
		log.Fatal(err)
	}

	// 创建DKIM签名选项
	options := &dkim.SignOptions{
		Domain:   "example.com",        // 你的域名
		Selector: "default",           // DKIM选择器
		Signer:   loadPrivateKey(),    // 加载私钥函数
		HeaderKeys: []string{          // 需要签名的头部字段
			"From",
			"To",
			"Subject",
			"Date",
			"Message-ID",
			"MIME-Version",
			"Content-Type",
		},
	}

	// 签名邮件
	var b bytes.Buffer
	if err := dkim.Sign(&b, msg, options); err != nil {
		log.Fatal(err)
	}

	// 输出签名后的邮件
	signedEmail := b.String()
	fmt.Println(signedEmail)
}

// 加载私钥 - 实际应用中应从安全存储中获取
func loadPrivateKey() crypto.Signer {
	// 示例私钥 - 实际应用中不应硬编码
	privateKey := `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAz6j7...` // 这里应该是你的实际私钥

	block, _ := pem.Decode([]byte(privateKey))
	if block == nil {
		log.Fatal("failed to decode PEM block containing private key")
	}

	key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		log.Fatal(err)
	}

	return key
}

DKIM验证实现

以下是验证DKIM签名的代码:

package main

import (
	"bytes"
	"fmt"
	"log"
	"strings"

	"github.com/emersion/go-dkim"
	"github.com/emersion/go-message/mail"
)

func main() {
	// 假设这是收到的已签名邮件
	signedEmail := `DKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=default;
		c=relaxed/relaxed; q=dns/txt; t=1624411200; h=From:To:Subject:Date:
		Message-ID:MIME-Version:Content-Type; bh=2jUSOH9NhtVGCQWNd9...;
		b=Ofjy3U3FQTDtg/4yJ1AK0XkDeoy0...
From: sender@example.com
To: recipient@example.com
Subject: Test DKIM Signed Email
Date: Mon, 23 Jun 2023 10:00:00 +0800
Message-ID: <123456789@example.com>
MIME-Version: 1.0
Content-Type: text/plain; charset="UTF-8"

This is a test email with DKIM signature.`

	// 解析邮件
	msg, err := mail.ReadMessage(strings.NewReader(signedEmail))
	if err != nil {
		log.Fatal(err)
	}

	// 创建验证器
	verifier := &dkim.Verifier{
		LookupTXT: lookupDKIMRecord, // 自定义DNS查询函数
	}

	// 验证邮件
	if err := verifier.Verify(msg); err != nil {
		log.Fatal("DKIM verification failed:", err)
	}

	fmt.Println("DKIM verification succeeded!")
}

// 自定义DNS查询函数
func lookupDKIMRecord(domain string) ([]string, error) {
	// 实际应用中应该执行真正的DNS查询
	// 这里只是示例,返回硬编码的DKIM公钥记录
	
	if domain == "default._domainkey.example.com" {
		return []string{
			"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz6j7...",
		}, nil
	}
	
	return nil, fmt.Errorf("no DKIM record found for %s", domain)
}

实际应用建议

  1. 私钥管理

    • 永远不要将私钥硬编码在代码中
    • 使用安全的密钥存储方案,如KMS、HashiCorp Vault等
    • 考虑定期轮换密钥
  2. DNS配置

    • 确保正确设置DKIM DNS记录
    • 记录格式通常为:selector._domainkey.yourdomain.com
  3. 签名策略

    • 选择适当的签名算法(推荐rsa-sha256)
    • 确定需要签名的头部字段(From字段必须包含)
    • 考虑签名过期时间
  4. 验证处理

    • 对于验证失败的邮件,可以记录日志或采取适当措施
    • 考虑将验证结果添加到邮件头中供后续处理

性能考虑

当处理大量邮件时:

  1. 可以重用DKIM签名器和验证器实例
  2. 考虑缓存DNS查询结果
  3. 对于高负载系统,可能需要实现并发处理

go-dkim库提供了灵活的接口,可以集成到各种邮件处理流程中,无论是作为邮件服务器的一部分,还是作为独立的邮件处理工具。

回到顶部