4

我正在将一些现有的 Python 代码移植到 Go。一位负责通过 Exchange 服务器(SMTP + STARTTLS)发送电子邮件。现有(简化)代码如下所示:

import smtplib
client = smtplib.SMTP("exchangeserver.com")
client.starttls()
client.login('user', 'password')
client.sendmail('user@exchangeserver.com', 
    ['otheruser1@exchangeserver.com', 'otheruser2@exchangeserver.com'], 
    '..message..')

我想用 Go 做同样的事情,感谢帮助 - 谢谢。

4

2 回答 2

5

要扩展Cory LaNou 的答案,您可以在普通的net.Conn. 您需要定义一个tls.Config然后使用它来升级连接以使用 TLS。

下面的示例基于 Cory 的回答,并且还从crypto/tls 测试文件中窃取了一些代码,用于创建 RSA 证书和私钥。在生产中,您显然会用真正的证书和密钥替换它们。

它可能需要对变量进行一些自定义,以及对变量进行一些更改以tls.Config适应您的环境。

package main

import (
    "crypto/rsa"
    "crypto/tls"
    "encoding/hex"
    "fmt"
    "log"
    "math/big"
    "net"
    "net/smtp"
)

func main() {

    var (
        host     = "smtp.myexchange.com"
        port     = 587
        from     = "sender@example.org"
        password = "password"
        to       = []string{"recipient@example.org"}
        msg      = []byte("This is my message")
        auth     = smtp.PlainAuth("", from, password, "smtp.myexchange.com")
    )

    conf := new(tls.Config)
    conf.Certificates = make([]tls.Certificate, 1)
    conf.Certificates[0].Certificate = [][]byte{testRSACertificate}
    conf.Certificates[0].PrivateKey = testRSAPrivateKey
    conf.CipherSuites = []uint16{tls.TLS_RSA_WITH_RC4_128_SHA}
    conf.InsecureSkipVerify = true
    conf.MinVersion = tls.VersionSSL30
    conf.MaxVersion = tls.VersionTLS10
    serverAddr := fmt.Sprintf("%s:%d", host, port)

    conn, err := net.Dial("tcp", serverAddr)
    if err != nil {
        log.Printf("Error Dialing %s\n", err)
        return
    }

    client, err := smtp.NewClient(conn, host)
    if err != nil {
        log.Printf("Error SMTP connection: %s\n", err)
        return
    }

    if err = client.StartTLS(conf); err != nil {
        log.Printf("Error performing StartTLS: %s\n", err)
        return
    }

    if ok, _ := client.Extension("AUTH"); ok {
        if err := client.Auth(auth); err != nil {
            log.Printf("Error during AUTH %s\n", err)
            return
        }
    }

    if err := client.Mail(from); err != nil {
        log.Printf("Error: %s\n", err)
        return
    }

    for _, addr := range to {
        if err := client.Rcpt(addr); err != nil {
            log.Printf("Error: %s\n", err)
            return
        }
    }

    w, err := client.Data()
    if err != nil {
        log.Printf("Error: %s\n", err)
        return
    }

    _, err = w.Write(msg)
    if err != nil {
        log.Printf("Error: %s\n", err)
        return

    }

    err = w.Close()
    if err != nil {
        log.Printf("Error: %s\n", err)
        return

    }

    client.Quit()
}

// Code below from http://golang.org/src/pkg/crypto/tls/handshake_server_test.go

func bigFromString(s string) *big.Int {
    ret := new(big.Int)
    ret.SetString(s, 10)
    return ret
}

func fromHex(s string) []byte {
    b, _ := hex.DecodeString(s)
    return b
}

var testRSACertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9")

var testRSAPrivateKey = &rsa.PrivateKey{
    PublicKey: rsa.PublicKey{
        N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
        E: 65537,
    },
    D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
    Primes: []*big.Int{
        bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
        bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
    },
}

操场

于 2014-03-02T05:21:57.360 回答
5

编辑:

这是使用 tls 连接设置的示例。我没有要测试的对象,因此在我的连接端失败了,但我怀疑这是使它工作所需的

package main

import (
  "crypto/tls"
  "fmt"
  "log"
  "net/smtp"
)

func main() {
  var (
    host     = "smtp.google.com"
    port     = 587
    from     = "foo@bar.com"
    password = "baz"
    to       = []string{"bin@bar.com"}
    msg      = []byte("This is my message")
    auth     = smtp.PlainAuth("", from, password, "smtp.gmail.com")
  )
  serverAddr := fmt.Sprintf("%s:%d", host, port)

  conn, err := tls.Dial("tcp", serverAddr, nil)
  if err != nil {
    log.Printf("Error Dialing %s\n", err)
    return
  }

  client, err := smtp.NewClient(conn, host)
  if err != nil {
    log.Printf("Error SMTP connection: %s\n", err)
    return
  }

  if ok, _ := client.Extension("AUTH"); ok {
    if err := client.Auth(auth); err != nil {
      log.Printf("Error during AUTH %s\n", err)
      return
    }
  }

  if err := client.Mail(from); err != nil {
    log.Printf("Error: %s\n", err)
    return
  }

  for _, addr := range to {
    if err := client.Rcpt(addr); err != nil {
      log.Printf("Error: %s\n", err)
      return
    }
  }

  w, err := client.Data()
  if err != nil {
    log.Printf("Error: %s\n", err)
    return
  }

  _, err = w.Write(msg)
  if err != nil {
    log.Printf("Error: %s\n", err)
    return

  }

  err = w.Close()
  if err != nil {
    log.Printf("Error: %s\n", err)
    return

  }

  client.Quit()
}

我认为这样的事情可能会奏效。您必须对服务器、用户/密码等进行适当的更改。如果您需要更多帮助,请告诉我。

package main

import (
  "fmt"
  "log"
  "net/smtp"
)

func main() {
  to := "foo@foo.com"
  from := "bin@baz.com"
  password := "myPassword"
  subject := "subject line of email"
  msg := "a one-line email message"

  emailTemplate := `To: %s
Subject: %s

%s
`
  body := fmt.Sprintf(emailTemplate, to, subject, msg)
  auth := smtp.PlainAuth("", from, password, "smtp.gmail.com")
  err := smtp.SendMail(
    "smtp.gmail.com:587",
    auth,
    from,
    []string{to},
    []byte(body),
  )
  if err != nil {
    log.Fatal(err)
  }
}
于 2014-03-01T22:54:35.727 回答