Help us understand the problem. What is going on with this article?

go で utf8メールを送信

More than 5 years have passed since last update.

asciiでの平文メールはnet/smtpで簡単に送信できるようですが、
http://kwmt27.net/index.php/2013/09/26/how-to-send-mail-with-golang/

utf8になると本文とsubjectのエンコード処理の面倒な部分を
やってくれるパッケージを探したんだけど見つからなかった。

本文はbase64でエンコードすれば良いんだけど、
subjectが若干面倒
http://d.hatena.ne.jp/y_fudi/20090501/1241173690

で、メールに関するお約束のRFC2822にこんな規定がある。ヘッダーに限定されているわけではないが、メールの1行に並べていい文字数には制限があるようだ。
http://www.puni.net/~mimori/rfc/rfc2822.txtより引用:
行の長さの制限
この標準では1行中の文字数に2つの制限がある。それぞれの行の文字はCRLFを除いて、決して998文字以下でなければならず(MUST)、78文字以下であるべきである(SHOULD)。
そんなわけで、MIMEエンコードされたSubjectがずらっと1行に並んでしまうと、うっかり998文字を超えてしまうおそれがあるわけで、なんとか78文字くらいで改行するのがよろしいということだろう。
ちなみに、上で使ったのと同じ文字列をBecky!2.50.07の件名の欄に突っ込んで、メールを送ってみたら、やっぱり適度に改行されていた。

Subject: =?ISO-2022-JP?B?GyRCJDMkbCRPJUYlOSVIJWEhPCVrJE4lNRsoQg==?=
=?ISO-2022-JP?B?GyRCJVYlOCUnJS8lSCQzJGwkTyVGJTklSBsoQg==?=
=?ISO-2022-JP?B?GyRCJWEhPCVrJE4lNSVWJTglJyUvJUgkMxsoQg==?=
=?ISO-2022-JP?B?GyRCJGwkTyVGJTklSCVhITwlayROJTUlVhsoQg==?=
=?ISO-2022-JP?B?GyRCJTglJyUvJUgkMyRsJE8lRiU5JUglYRsoQg==?=
=?ISO-2022-JP?B?GyRCITwlayROJTUlViU4JSclLyVIJDMkbBsoQg==?=
=?ISO-2022-JP?B?GyRCJE8lRiU5JUglYSE8JWskTiU1JVYlOBsoQg==?=
=?ISO-2022-JP?B?GyRCJSclLyVIGyhC?=

76文字以内(改行含めず)で収まるように適度に改行してmimeエンコードした上で先頭にスペースを入れるのがよさそう

サンプルを書いた。

go-utf8-sendmail-example.go
package main

import (
    "bytes"
    "encoding/base64"
    "log"
    "net/mail"
    "net/smtp"
    "strings"
)

// 76バイト毎にCRLFを挿入する
func add76crlf(msg string) string {
    var buffer bytes.Buffer
    for k, c := range strings.Split(msg, "") {
        buffer.WriteString(c)
        if k%76 == 75 {
            buffer.WriteString("\r\n")
        }
    }
    return buffer.String()
}

// UTF8文字列を指定文字数で分割
func utf8Split(utf8string string, length int) []string {
    resultString := []string{}
    var buffer bytes.Buffer
    for k, c := range strings.Split(utf8string, "") {
        buffer.WriteString(c)
        if k%length == length-1 {
            resultString = append(resultString, buffer.String())
            buffer.Reset()
        }
    }
    if buffer.Len() > 0 {
        resultString = append(resultString, buffer.String())
    }
    return resultString
}

// サブジェクトをMIMEエンコードする
func encodeSubject(subject string) string {
    var buffer bytes.Buffer
    buffer.WriteString("Subject:")
    for _, line := range utf8Split(subject, 13) {
        buffer.WriteString(" =?utf-8?B?")
        buffer.WriteString(base64.StdEncoding.EncodeToString([]byte(line)))
        buffer.WriteString("?=\r\n")
    }
    return buffer.String()
}

func main() {


    from := mail.Address{"ふろむ", "from@hoge.fuga"}
    to := mail.Address{"とぅー", "to@fuga.hoge"}
    title := "長いサブジェクト長いサブジェクト長いサブジェクト長いサブジェクト長いサブジェクト長いサブジェクト長いサブジェクト"

    var body bytes.Buffer
    body.WriteString("本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文\n")
    body.WriteString("本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文\n")

    var header bytes.Buffer
    header.WriteString("From: " + from.String() + "\r\n")
    header.WriteString("To: " + to.String() + "\r\n")
    header.WriteString(encodeSubject(title))
    header.WriteString("MIME-Version: 1.0\r\n")
    header.WriteString("Content-Type: text/plain; charset=\"utf-8\"\r\n")
    header.WriteString("Content-Transfer-Encoding: base64\r\n")

    var message bytes.Buffer
    message = header
    message.WriteString("\r\n")
    message.WriteString(add76crlf(base64.StdEncoding.EncodeToString(body.Bytes())))

    err := smtp.SendMail(
        "localhost:25",
        nil,
        from.Address,
        []string{to.Address},
        []byte(message.String()),
    )
    if err != nil {
        log.Fatal(err)
    }
}

これで送信するとこんな感じになった

Subject: =?utf-8?B?6ZW344GE44K144OW44K444Kn44Kv44OI6ZW344GE44K144OW44K4?=
 =?utf-8?B?44Kn44Kv44OI6ZW344GE44K144OW44K444Kn44Kv44OI6ZW344GE?=
 =?utf-8?B?44K144OW44K444Kn44Kv44OI6ZW344GE44K144OW44K444Kn44Kv?=
 =?utf-8?B?44OI6ZW344GE44K144OW44K444Kn44Kv44OI6ZW344GE44K144OW?=
 =?utf-8?B?44K444Kn44Kv44OI?=
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
Message-Id: <20140222115231.8DECE260593@st>
Date: Sat, 22 Feb 2014 20:52:31 +0900 (JST)

5pys5paH5pys5paH5pys5paH5pys5paH5pys5paH5pys5paH5pys5paH5pys5paH5pys5paH5pys
5paH5pys5paH5pys5paH5pys5paH5pys5paH5pys5paH5pys5paH5pys5paH5pys5paHCuacrOaW
h+acrOaWh+acrOaWh+acrOaWh+acrOaWh+acrOaWh+acrOaWh+acrOaWh+acrOaWh+acrOaWh+ac
rOaWh+acrOaWh+acrOaWh+acrOaWh+acrOaWh+acrOaWh+acrOaWh+acrOaWhwo=
yamasaki-masahide
インフラ関連技術に興味があります。 暇があればgolangで何か作りたい
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away