go发送邮件

作者: 我傻笑你跑掉 | 来源:发表于2021-02-01 18:20 被阅读0次

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式,绝大多数语言如C++ Java等都通过库的方式支持了他,当然,go语言也不会例外

    很重要

    这个一定要写在前面,建议自己尝试的时候呢,多申请几个邮箱.
    不要用自己的常用邮箱.
    不要用自己的常用邮箱.
    不要用自己的常用邮箱.
    国内大多数邮箱都有数量限制,单日发的太多容易被封.

    smtp库

    smtp标准库就是golang实现邮件发送的一个标准库,你可以查看src中的net/stmp来查看他的源码

    stmp库只有两个文件,auth.gosmtp.go,前者是用来验证的,后者是用发发送邮件的,auth.go比较简单,通常也不会自己去实现,所以仅做了解即可,用发是固定的,后面的例子会演示

    我们主要来看一下smtp.go中的SendMail()方法,下面为函数签名

    func SendMail(addr string, a Auth, from string, to []string, msg []byte) error {}
    

    参数含义如下
    addr  邮件服务器地址,一般与端口一起,如腾讯的邮箱 smtp.exmail.qq.com:25
    a       通过Auth.go中的PlainAuth()方法验证发件人用户名密码后获得
    from  发件人邮箱
    to      收件人邮箱列表
    msg   邮件内容

    利用smtp来发送邮件

    smtp库不需要我们视线接口,我们只需要构造好参数,通过SendMail()来发送邮件即可

    我们来模拟向腾讯邮箱中发送一封邮件,首先来构造参数,腾讯邮件服务器地址为smtp.qq.com,端口为25(大部分邮件服务器的端口都是25),常用邮箱的邮件服务器地址我会在最后在备注中贴出

    addr := "smtp.qq.com:25"
    

    除此之外,我们还需要构造a,from,to,msg四个参数

    首先 使用auth.go中的PlainAuth()来生成a,也就是Auth类型,这边是需要发件人的邮箱,邮件服务器,邮箱密码,我这里演示通过我的一个qq邮箱向我的另外一个qq邮箱发送邮件

    获取auth时如果不是TLS连接第一个参数可以给空字符串,我们一般邮件都不需要指定第一个参数,后面参数就分别为 邮箱 密码 邮箱所在的邮件服务器

    auth := smtp.PlainAuth("", "你的qq号码@qq.com", "password", "smtp.qq.com")
    

    from发件人也就是上面验证auth用到的邮箱,zhangsheng_1992@sohu.com

    from := "你的qq号码@qq.com"
    

    to为收件人,是一个[]string

    to := []string{"收件人qq号码@qq.com"}
    

    最后是msg

    msg := []byte("Hello World!")
    

    整体代码如下:

    package main
    
    import (
        "fmt"
        "net/smtp"
    )
    
    func main() {
        addr := "smtp.qq.com:25"
        auth := smtp.PlainAuth("", "115354xxxxx@qq.com", "password", "smtp.qq.com")
        from := "115354xxxxx@qq.com"
        to := []string{"2974xxxxx@qq.com"}
        msg := []byte("Hello World!")
        err := smtp.SendMail(addr, auth, from, to, msg)
        fmt.Println(err)
    }
    

    注意: 大部分个人邮箱都有smtp保护,所以你可能需要登陆邮箱设置一下

    比如qq邮箱你需要设置一个授权码,保护你的密码嘛
    点击设置,账户,开启pop3/smtp邮件保护,开启服务的第一个选项,根据提示获取授权码,然后在上面程序密码处填写授权码


    qqmail.png

    而sohu邮箱就简单些,勾选开启服务即可


    sohumail.png

    其他邮箱的设置大同小异,请自行设置,运行程序,然后去邮箱查看


    receivemail.png

    构造邮件头

    我门发现上面收到的邮件没有标题,也没有发件人,更没有收件人及内容信息,这是为什么呢?

    其实这部分信息在msg中,需要我们来构造,包括
    subject 邮件标题
    send 邮件接收人,与上面的from区分开,所以我改个名字
    receiver 邮件接收人
    type 邮件类型 如html邮件 纯文本邮件等等

    我门来构造这一部分,注意,这些参数全部时字符串,我们使用fmt.Sprintf()方法来生成这个string,\r\n表示换行,固定格式

        subject := fmt.Sprintf("Subject: %s\r\n", "测试邮件")
        send := fmt.Sprintf("From: %s 测试发件邮箱\r\n", "11535xxx.com")
        receiver := fmt.Sprintf("To: %s\r\n", "2974xxx@qq.com")
        content_type := "Content-Type: text/plain" + "; charset=UTF-8\r\n\r\n"
        content := "Hello World!"
        msg := []byte(subject + send + receiver + content_type + content)
        addr := "smtp.qq.com:25"
        auth := smtp.PlainAuth("", "11535xxxxx@qq.com", "password", "smtp.qq.com")
        from := "11535xxxxx@qq.com"
        to := []string{"2974xxxxx@qq.com"}
        err := smtp.SendMail(addr, auth, from, to, msg)
        fmt.Println(err)
    

    这次我们来看接收到的邮件

    receivemail2.png

    是不是信息都全了?

    关于邮件头,需要记住
    1.它们都是字符串拼接而成的,顺序为
    邮件标题 \r\n
    发件人 \r\n
    收件人 \r\n
    邮件类型与字符编码 \r\n\r\n
    邮件内容

    2.邮件类型与邮件内容之间需要2个换行,即2组\r\n,否则无法看到邮件内容,就如同第一次那样

    3.如果接收到的邮件为乱码,那么检查字符编码

    发送html邮件

    发送html邮件,仅需要设置content_type,也就是邮件类型中的Content-Type: text/html;即:

    content_type = "Content-Type: text/html; charset=UTF-8\r\n\r\n" //和邮件内容间两组换行
    

    一般我门不会把html当做一个字符串写到程序中,那样修改起来很麻烦,我们通常的做法是将html写成一个模版,然后读区这个模版,新建一个temp.html,内容如下:

    <html>
        <head>
            <meta charset="utf-8" />
            <title>测试邮件</title>
        </head>
    
        <body>
                <p class="title">我是测试邮件</p>
                <p>内容1: %s</p>
                <p>内容2: %s</p>
                <img src="%s" alt="图片"/>
                <p><a href="%s">查看详情</a>
        </body>
    </html>
    

    然后通过os.Open()打开并读取这个模版

    file, _ := os.Open("temp.html")
        defer file.Close()
        p := make([]byte, 2<<10)//设置大一点 让一次性读进去
        if _, err := file.Read(p); err != nil {
            fmt.Println(err)
            os.Exit(0)
        }
        content := fmt.Sprintf(string(p), "1", "2", "http://img3.doubanio.com/lpic/s24524807.jpg", "4")//去网上随便找的张图 测试而已,如果你收到的邮件图片打不开请换一个图片链接(随便网上找张图,右键获取图片地址)
    

    其他部分不变,记得设置content_type 编码,再次发送

    golang的吉祥物就被我们通过邮件发出去了,当然你还可以增加一些css和js来丰富一封html邮件的,但这不是本文重点

    完整代码

    package main
    
    import (
        "fmt"
        "net/smtp"
        "os"
    )
    
    func main() {
        file, _ := os.Open("temp.html")
        defer file.Close()
        p := make([]byte, 2<<10)
        if _, err := file.Read(p); err != nil {
            fmt.Println(err)
            os.Exit(0)
        }
        content := fmt.Sprintf(string(p), "1", "2", "http://img3.doubanio.com/lpic/s24524807.jpg", "4")
        subject := fmt.Sprintf("Subject: %s\r\n", "测试邮件")
        send := fmt.Sprintf("From: %s 测试发件邮箱\r\n", "11535xxxxx.com")
        receiver := fmt.Sprintf("To: %s\r\n", "2974xxxxx@qq.com")
        content_type := "Content-Type: text/html" + "; charset=UTF-8\r\n\r\n"
        msg := []byte(subject + send + receiver + content_type + content)
        addr := "smtp.qq.com:25"
        auth := smtp.PlainAuth("", "11535xxxxx@qq.com", "paaword", "smtp.qq.com")
        from := "11535xxxxx@qq.com"
        to := []string{"2974xxxxx@qq.com"}
        err := smtp.SendMail(addr, auth, from, to, msg)
        fmt.Println(err)
    }
    

    发送附件

    一个标准的邮件包含 邮件头,邮件内容,附件,下面,我就来介绍如何发送一个带附件的邮件
    与发送html相同,发送一个带附件的邮件,也需要指定Content-Type参数,并指定一个分隔符,将邮件头,正文部分附件分隔开,分隔符可以任意设置

    content_type := "Content-Type: multipart/mixed; boundary=分隔符\r\n"
    

    分隔符以 --分隔符 开头,以--分隔符--结尾,然后,为了兼容性,需要将附件编码,为了增加理解,我在代码中增加了过多注释,可能影响阅读体验,建议拷贝下来自己边运行边理解,一定要注意换行!!!!

    package main
    import (
        "encoding/base64"
        "fmt"
        //  "io/ioutil"
        "net/smtp"
        "os"
    )
    func main() {
        //mailcontent用来保存邮件的有所内容
        var mailcontent string
        //设置内容间的分隔符 尽量不要用汉字,除此之外设置成什么都可以
        delimiter := "module"
        //设置头信息头部分
        subject := fmt.Sprintf("Subject: %s\r\n", "测试邮件")
        send := fmt.Sprintf("From: %s 测试发件邮箱\r\n", "11535xxxxx@qq.com")
        receiver := fmt.Sprintf("To: %s\r\n", "2974xxxxx@qq.com") + "MIME-Version: 1.0\r\n"
        content_type := "Content-Type: multipart/mixed; boundary=" + delimiter + "\r\n"
        //邮件描述 这个可以不设置也没关系
        content_type += "Content-Description: 我有附件\r\n"
        header := subject + send + receiver + content_type
        //邮件头部分设置完毕
    
        //分割头信息与普通文本邮件 重要!!!!!!!
        mailcontent = header + fmt.Sprintf("\r\n--%s\r\n", delimiter)
        //你可以同时发送html 但需要注意分隔 你可以把这段注释掉只发送html邮件
        htmlcontent := "Content-Type: text/html; charset=UTF-8\r\n\r\n"
        htmlcontent += `<html><head></head><body><h1 style="color:red">我是html内容</h1></body></html>`
        mailcontent += htmlcontent
    
        //附件部分
        filepath := "/Users/zhangsheng/go/a.png"
        filename := "a.png"
        //分隔 html内容与附件内容
        fileheader := fmt.Sprintf("\r\n--%s\r\n", delimiter)
        fileheader += "Content-Type: application/octet-stream\r\n"
        fileheader += "Content-Description: 附一个Go文件\r\n"
        fileheader += "Content-Transfer-Encoding: base64\r\n"
        fileheader += "Content-Disposition: attachment; filename=\"" + filename + "\"\r\n\r\n"
    
        //读取附件内容并编码
        file, _ := os.Open(filepath)
        fileinfo := make([]byte, 2<<16)//这边需要设置一个足够大的容量来保证可以一次性读取,后面学习ioutil和bufio库的时候会学习到更简便的办法
        if n, err := file.Read(fileinfo); err != nil {
            fmt.Println(err)
        } else {
            fileinfo = fileinfo[:n]
        }
        filecontent := base64.StdEncoding.EncodeToString(fileinfo)
        // 我们可以使用ioutil库来实现读取 这样就不用像os Read()设置一个足够大的[]byte
        //  fileinfo, _ := ioutil.ReadFile(filepath)
        //  filecontent := make([]byte, base64.StdEncoding.EncodedLen(len(attaData)))
        //  base64.StdEncoding.Encode(filecontent, attaData)
        filemessage := fileheader + filecontent
        //分隔结束
        mailcontent += filemessage + "\r\n--" + delimiter + "--\r\n\r\n"
    
        msg := []byte(mailcontent)
        fmt.Println(string(msg))
        addr := "smtp.qq.com:25"
        auth := smtp.PlainAuth("", "11535xxxxx@qq.com", "password", "smtp.qq.com")
        from := "11535xxxxx@qq.com"
        to := []string{"297xxxxx@qq.com"}
        err := smtp.SendMail(addr, auth, from, to, msg)
        fmt.Println(err)
    }
    

    输出的内容如下:
    Subject: 测试邮件
    From: 11535xxxxx@qq.com 测试发件邮箱
    To: 2974xxxxx@qq.com
    MIME-Version: 1.0
    Content-Type: multipart/mixed; boundary=module  看这里!我设置的分隔符叫module
    Content-Description: 这是一封带附档的邮件

    --module 第一个分隔符将邮件人信息与邮件内容分隔开
    Content-Type: text/html; charset=UTF-8

    <html><head></head><body><h1 style="color:red">我是html内容</h1></body></html>
    --module 第二个分隔符 将邮件内容与附件分隔开
    Content-Type: application/octet-stream
    Content-Description: 附一个Png文件
    Content-Transfer-Encoding: base64
    Content-Disposition: attachment; filename="a.png"
    //这里是很长的一串编码后的结果
    --module-- 分隔符结束

    如果你要发送多个附件,简单,继续用分隔符分开第一个附件与第二个区分开即可

    然后取接收邮件吧


    attr.png htmlattrmail.png

    邮件群发

    群发邮件也非常简单,无论是简单文件还是html文件
    首先在receiver里用;隔开收件人,如:

    receiver := fmt.Sprintf("To: %s\r\n", "2974xxxxx@qq.com;b.qq.com;c.qq.com")
    

    然后在to切片中也增加收件人就可以啦

    to := []string{"2974xxxxx@qq.com","b.qq.com","c.qq.com"}
    

    总结

    本章我门讲解了smtp库的m,他实现了邮件发送的规则并且可以用来发送邮件,我们讲解了普通邮件,html邮件和附件,以及组合类型邮件,由于邮件和html并不是讲解重点,所以很多东西并没有讲的很细,比如Content-Type,html只是 分隔符 还有包括内嵌邮件等其他使用上的东西

    但掌握了smtp库的用法以后,你仅需要取了解这部分内容,并按要求构造你的邮件字符串就可以

    附件--常用邮箱地址

    注:pop3为收件箱地址,一些客户端邮件管理程序会使用这个
    IMAP是另外一种邮件协议 我门常用的都是SMTP协议

    阿里云邮箱(mail.aliyun.com):
    POP3服务器地址:pop3.aliyun.com(SSL加密端口:995;非加密端口:110)
    SMTP服务器地址:smtp.aliyun.com(SSL加密端口:465;非加密端口:25)
    IMAP服务器地址:imap.aliyun.com(SSL加密端口:993;非加密端口:143)

    谷歌邮箱(google.com):
    POP3服务器地址:pop.gmail.com(SSL启用端口:995)
    SMTP服务器地址:smtp.gmail.com(SSL启用端口:587)

    新浪邮箱(sina.com):
    POP3服务器地址:pop3.sina.com.cn(端口:110)
    SMTP服务器地址:smtp.sina.com.cn(端口:25)

    Tom邮箱(top.com):
    POP3服务器地址:pop.tom.com(端口:110)
    SMTP服务器地址:smtp.tom.com(端口:25)

    网易邮箱(163.com):
    POP3服务器地址:pop.163.com(端口:110)
    SMTP服务器地址:smtp.163.com(端口:25)

    126邮箱:
    POP3服务器地址:pop.live.com(端口:995)
    SMTP服务器地址:smtp.126.com(端口:25)

    雅虎邮箱(yahoo.com):
    POP3服务器地址:pop.mail.yahoo.com
    SMTP服务器地址:smtp.mail.yahoo.com

    雅虎中国(yahoo.com.cn):
    POP3服务器地址:pop.mail.yahoo.com.cn(端口:995)
    SMTP服务器地址:smtp.mail.yahoo.com.cn(端口:587)
    雅虎邮箱POP3的SSL不启用端口为110,POP3的SSL启用端口995;SMTP的SSL不启用端口为25,SMTP的SSL启用端口为465。

    Foxmail邮箱(foxmail.com):
    POP3服务器地址:POP.foxmail.com(端口:110)
    SMTP服务器地址:SMTP.foxmail.com(端口:25)

    QQ邮箱(mail.qq.com)
    POP3服务器地址:pop.qq.com(端口:110)
    SMTP服务器地址:smtp.qq.com(端口:25)
    SMTP服务器需要身份验证。

    搜狐邮箱(sohu.com):
    POP3服务器地址:pop3.sohu.com(端口:110)
    SMTP服务器地址:smtp.sohu.com(端口:25)

    HotMail邮箱(hotmail.com):
    POP3服务器地址:pop.live.com(端口:995)
    SMTP服务器地址:smtp.live.com(端口:587

    移动139邮箱:
    POP3服务器地址:POP.139.com(端口:110)
    SMTP服务器地址:SMTP.139.com(端口:25)

    中华网邮箱(china.com):
    POP3服务器地址:pop.china.com(端口:110)
    SMTP服务器地址:smtp.china.com(端口:25)

    相关文章

      网友评论

        本文标题:go发送邮件

        本文链接:https://www.haomeiwen.com/subject/pulstltx.html