Golang实现Office 365邮件发送功能指南

Golang实现Office 365邮件发送功能指南 我有以下 main.go 代码用于解析 HTML 模板并通过电子邮件发送:

package main

import (
  "bytes"
  "fmt"
  "net/smtp"
  "text/template"
)

func main() {

  // 发件人信息。
  from := "from@gmail.com"
  password := "<Email Password>"

  // 收件人邮箱地址。
  to := []string{
    "sender@example.com",
  }

  // SMTP 服务器配置。
  smtpHost := "smtp.gmail.com"
  smtpPort := "587"

  // 身份验证。
  auth := smtp.PlainAuth("", from, password, smtpHost)

  t, _ := template.ParseFiles("template.html")

  var body bytes.Buffer

  mimeHeaders := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
  body.Write([]byte(fmt.Sprintf("Subject: This is a test subject \n%s\n\n", mimeHeaders)))

  t.Execute(&body, struct {
    Name    string
    Message string
  }{
    Name:    "Hasan yousef",
    Message: "This is a test message in a HTML template",
  })

  // 发送邮件。
  err := smtp.SendMail(smtpHost+":"+smtpPort, auth, from, to, body.Bytes())
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("Email Sent!")
}

以及以下模板:

<!-- template.html -->
<!DOCTYPE html>
<html>
<body>
    <h3>Name:</h3><span>{{.Name}}</span><br/><br/>
    <h3>Email:</h3><span>{{.Message}}</span><br/>
</body>
</html>

这段代码运行得非常顺利。

我尝试使用我的 Office 365 邮箱做同样的事情,配置如下:

smtpHost := "smtp.office365.com"
smtpPort := "587"

但是未能成功,并返回以下错误:

504 5.7.4 Unrecognized authentication type [ZR0P278CA0020.CHEP278.PROD.OUTLOOK.COM]

对于 Gmail,我启用了 使用不够安全的应用 选项,使得 smtp.PlainAuth 能够正常工作。对于 Office 365,我知道其 加密方法:TLS 或 STARTTLS,但不知道如何在我的代码中实现它?


更多关于Golang实现Office 365邮件发送功能指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

我找到了正确的答案,在此分享以供社区参考:

package main

import (
    "bytes"
    "crypto/tls"
    "errors"
    "fmt"
    "net"
    "net/smtp"
    "text/template"
)

type loginAuth struct {
    username, password string
}

func LoginAuth(username, password string) smtp.Auth {
    return &loginAuth{username, password}
}

func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
    return "LOGIN", []byte(a.username), nil
}

func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
    if more {
        switch string(fromServer) {
        case "Username:":
            return []byte(a.username), nil
        case "Password:":
            return []byte(a.password), nil
        default:
            return nil, errors.New("Unknown from server")
        }
    }
    return nil, nil
}

func main() {

    // 发件人数据。
    from := "O365 登录名"
    password := "O365 登录密码"

    // 收件人邮箱地址。
    to := []string{
        "收件人邮箱",
    }

    // SMTP 服务器配置。
    smtpHost := "smtp.office365.com"
    smtpPort := "587"

    conn, err := net.Dial("tcp", "smtp.office365.com:587")
    if err != nil {
        println(err)
    }

    c, err := smtp.NewClient(conn, smtpHost)
    if err != nil {
        println(err)
    }

    tlsconfig := &tls.Config{
        ServerName: smtpHost,
    }

    if err = c.StartTLS(tlsconfig); err != nil {
        println(err)
    }

    auth := LoginAuth(from, password)

    if err = c.Auth(auth); err != nil {
        println(err)
    }

    t, _ := template.ParseFiles("template.html")

    var body bytes.Buffer

    mimeHeaders := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
    body.Write([]byte(fmt.Sprintf("Subject: 这是一个测试主题 \n%s\n\n", mimeHeaders)))

    t.Execute(&body, struct {
        Name    string
        Message string
    }{
        Name:    "Hasan Yousef",
        Message: "这是 HTML 模板中的测试消息",
    })

    // 发送邮件。
    err = smtp.SendMail(smtpHost+":"+smtpPort, auth, from, to, body.Bytes())
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("邮件已发送!")
}

附上以下模板作为额外内容 🙂

<!-- template.html -->
<!DOCTYPE html>
<html>
<body>
    <h3>姓名:</h3><span>{{.Name}}</span><br/><br/>
    <h3>邮件:</h3><span>{{.Message}}</span><br/>
</body>
</html>

更多关于Golang实现Office 365邮件发送功能指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


对于Office 365的SMTP认证,需要使用STARTTLS而不是普通的PlainAuth。以下是修改后的代码:

package main

import (
    "bytes"
    "crypto/tls"
    "fmt"
    "net/smtp"
    "text/template"
)

func main() {
    // Office 365发件人信息
    from := "your_email@yourdomain.com"
    password := "your_password"
    
    // 收件人
    to := []string{"recipient@example.com"}
    
    // Office 365 SMTP配置
    smtpHost := "smtp.office365.com"
    smtpPort := "587"
    
    // 解析模板
    t, err := template.ParseFiles("template.html")
    if err != nil {
        fmt.Println("Error parsing template:", err)
        return
    }
    
    // 构建邮件内容
    var body bytes.Buffer
    
    // 设置邮件头
    headers := make(map[string]string)
    headers["From"] = from
    headers["To"] = to[0]
    headers["Subject"] = "This is a test subject"
    headers["MIME-Version"] = "1.0"
    headers["Content-Type"] = "text/html; charset=\"UTF-8\""
    
    // 写入头部
    for k, v := range headers {
        body.WriteString(fmt.Sprintf("%s: %s\r\n", k, v))
    }
    body.WriteString("\r\n")
    
    // 执行模板
    err = t.Execute(&body, struct {
        Name    string
        Message string
    }{
        Name:    "Hasan yousef",
        Message: "This is a test message in a HTML template",
    })
    if err != nil {
        fmt.Println("Error executing template:", err)
        return
    }
    
    // 连接到SMTP服务器
    client, err := smtp.Dial(fmt.Sprintf("%s:%s", smtpHost, smtpPort))
    if err != nil {
        fmt.Println("Error connecting to SMTP:", err)
        return
    }
    defer client.Close()
    
    // 启用STARTTLS
    err = client.StartTLS(&tls.Config{
        ServerName: smtpHost,
    })
    if err != nil {
        fmt.Println("Error starting TLS:", err)
        return
    }
    
    // 认证
    auth := smtp.PlainAuth("", from, password, smtpHost)
    err = client.Auth(auth)
    if err != nil {
        fmt.Println("Error authenticating:", err)
        return
    }
    
    // 设置发件人
    err = client.Mail(from)
    if err != nil {
        fmt.Println("Error setting sender:", err)
        return
    }
    
    // 设置收件人
    for _, recipient := range to {
        err = client.Rcpt(recipient)
        if err != nil {
            fmt.Println("Error setting recipient:", err)
            return
        }
    }
    
    // 发送邮件数据
    w, err := client.Data()
    if err != nil {
        fmt.Println("Error getting data writer:", err)
        return
    }
    
    _, err = w.Write(body.Bytes())
    if err != nil {
        fmt.Println("Error writing data:", err)
        return
    }
    
    err = w.Close()
    if err != nil {
        fmt.Println("Error closing writer:", err)
        return
    }
    
    fmt.Println("Email Sent Successfully!")
}

如果仍然遇到认证问题,可以尝试使用以下替代方法:

package main

import (
    "bytes"
    "fmt"
    "net/smtp"
    "text/template"
)

func main() {
    from := "your_email@yourdomain.com"
    password := "your_password"
    to := []string{"recipient@example.com"}
    
    smtpHost := "smtp.office365.com"
    smtpPort := "587"
    
    // 使用LoginAuth(如果PlainAuth不工作)
    auth := LoginAuth(from, password)
    
    t, _ := template.ParseFiles("template.html")
    
    var body bytes.Buffer
    
    mimeHeaders := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
    body.Write([]byte(fmt.Sprintf("Subject: This is a test subject \n%s\n\n", mimeHeaders)))
    
    t.Execute(&body, struct {
        Name    string
        Message string
    }{
        Name:    "Hasan yousef",
        Message: "This is a test message in a HTML template",
    })
    
    err := smtp.SendMail(smtpHost+":"+smtpPort, auth, from, to, body.Bytes())
    if err != nil {
        fmt.Println("Error sending email:", err)
        return
    }
    fmt.Println("Email Sent!")
}

// LoginAuth 实现LOGIN认证机制
type loginAuth struct {
    username, password string
}

func LoginAuth(username, password string) smtp.Auth {
    return &loginAuth{username, password}
}

func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
    return "LOGIN", []byte{}, nil
}

func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
    if more {
        switch string(fromServer) {
        case "Username:":
            return []byte(a.username), nil
        case "Password:":
            return []byte(a.password), nil
        }
    }
    return nil, nil
}

确保Office 365账户已启用SMTP访问,并且密码正确。如果启用了多重身份验证,需要使用应用专用密码。

回到顶部