热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Go每日一库之email

程序中时常有发送邮件的需求。有异常情况了需要通知管理员和负责人,用户下单后可能需要通知订单信息,电商平台、中国移动和联通都有每月账单,这些都可以通过邮件来推送。还有我们平时收到的垃圾邮件大都也是通过这种方式发送的:sob:。那么如何在Go语言发送邮件?本文我们介绍一下这个库的使用快不了,为什么呢?先安装库,这个自不必说:

简介

程序中时常有发送邮件的需求。有异常情况了需要通知管理员和负责人,用户下单后可能需要通知订单信息,电商平台、中国移动和联通都有每月账单,这些都可以通过邮件来推送。还有我们平时收到的垃圾邮件大都也是通过这种方式发送的:sob:。那么如何在 Go 语言发送邮件?本文我们介绍一下 email 库的使用。

快速使用

这个库的使用快不了,为什么呢?

先安装库,这个自不必说:

$ go get github.com/jordan-wright/email

我们需要额外一些工作。我们知道邮箱使用 STMP/POP3/IMAP 等协议从邮件服务器上拉取邮件。邮件并不是直接发送到邮箱的,而是邮箱请求拉取的。

所以,我们需要配置 STMP/POP3/IMAP 服务器。从头搭建固然可行,而且也有现成的开源库,但是比较麻烦。现在一般的邮箱服务商都开放了 STMP/POP3/IMAP 服务器。

我这里拿 126 邮箱来举例,使用 STMP 服务器。当然,用 QQ 邮箱也可以。

POP3/STMP/IMAP
IMAP/STMP

然后就可以编码了:

package main

import (
  "log"
  "net/smtp"

  "github.com/jordan-wright/email"
)

func main() {
  e := email.NewEmail()
  e.From = "dj "
  e.To = []string{"935653229@qq.com"}
  e.Subject = "Awesome web"
  e.Text = []byte("Text Body is, of course, supported!")
  err := e.Send("smtp.126.com:25", smtp.PlainAuth("", "xxx@126.com", "yyy", "smtp.126.com"))
  if err != nil {
    log.Fatal(err)
  }
}

这里为了我的信息安全,我把真实信息都隐藏了。代码中 xxx 替换成你的邮箱账号, yyy 替换成上面设置的密码。

代码步骤比较简单清晰:

  • 先调用 NewEmail 创建一封邮件;
  • 设置 From 发送方, To 接收者, Subject 邮件主题(标题), Text 设置邮件内容;
  • 然后调用 Send 发送,参数1是 STMP 服务器的地址,参数2为验证信息。

运行程序将会向我的 QQ 邮箱发送一封邮件:

Go 每日一库之 email

有的邮箱会把这种邮件放在垃圾箱中,例如 QQ:sob:。如果收件箱找不到,记得到垃圾箱瞅瞅。

抄送

平常我们发邮件的时候可能会抄送给一些人,还有一些人要 秘密抄送 :smile:,即 CC(Carbon Copy)和 BCC (Blind Carbon Copy)。

email 我们也可以设置这两个参数:

package main

import (
  "log"
  "net/smtp"

  "github.com/jordan-wright/email"
)

func main() {
  e := email.NewEmail()
  e.From = "dj "
  e.To = []string{"935653229@qq.com"}
  e.Cc = []string{"test1@126.com", "test2@126.com"}
  e.Bcc = []string{"secret@126.com"}
  e.Subject = "Awesome web"
  e.Text = []byte("Text Body is, of course, supported!")
  err := e.Send("smtp.126.com:25", smtp.PlainAuth("", "xxx@126.com", "yyy", "smtp.126.com"))
  if err != nil {
    log.Fatal(err)
  }
}

还是一样的,抄送的邮箱自己替换 test1/test2/secret 用自己的。

运行程序将会向我的 QQ 邮件发送一封邮件,同时抄送一封到我另一个 126 邮箱:

Go 每日一库之 email

Go 每日一库之 email

HTML 格式

发送纯文本,邮件不太美观。 email 支持发送 HTML 格式的内容。与发送纯文本类似,直接设置对象的 HTML 字段:

package main

import (
  "log"
  "net/smtp"

  "github.com/jordan-wright/email"
)

func main() {
  e := email.NewEmail()
  e.From = "dj "
  e.To = []string{"935653229@qq.com"}
  e.Cc = []string{"xxx@126.com"}
  e.Subject = "Go 每日一库"
  e.HTML = []byte(`
  
  `)
  err := e.Send("smtp.126.com:25", smtp.PlainAuth("", "xxx@126.com", "yyy", "smtp.126.com"))
  if err != nil {
    log.Fatal("failed to send email:", err)
  }
}

发送结果:

Go 每日一库之 email

注意,126 的 STMP 服务器检测比较严格,加上 HTML 之后,很容易被识别为垃圾邮件不让发送,这时 CC 自己就 OK 了。

附件

添加附件也很容易,直接调用 AttachFile 即可:

package main

import (
  "log"
  "net/smtp"

  "github.com/jordan-wright/email"
)

func main() {
  e := email.NewEmail()
  e.From = "dj "
  e.To = []string{"935653229@qq.com"}
  e.Subject = "Go 每日一库"
  e.Text = []byte("请看附件")
  e.AttachFile("test.txt")
  err := e.Send("smtp.126.com:25", smtp.PlainAuth("", "xxx@126.com", "yyy", "smtp.126.com"))
  if err != nil {
    log.Fatal("failed to send email:", err)
  }
}

收到的邮件:

Go 每日一库之 email

连接池

实际上每次调用 Send 时都会和 STMP 服务器建立一次连接,如果发送邮件很多很频繁的话可能会有性能问题。 email 提供了连接池,可以复用网络连接:

package main

import (
  "fmt"
  "log"
  "net/smtp"
  "os"
  "sync"
  "time"

  "github.com/jordan-wright/email"
)

func main() {
  ch := make(chan *email.Email, 10)
  p, err := email.NewPool(
    "smtp.126.com:25",
    4,
    smtp.PlainAuth("", "leedarjun@126.com", "358942617ldj", "smtp.126.com"),
  )

  if err != nil {
    log.Fatal("failed to create pool:", err)
  }

  var wg sync.WaitGroup
  wg.Add(4)
  for i := 0; i <4; i++ {
    go func() {
      defer wg.Done()
      for e := range ch {
        err := p.Send(e, 10*time.Second)
        if err != nil {
          fmt.Fprintf(os.Stderr, "email:%v sent error:%v\n", e, err)
        }
      }
    }()
  }

  for i := 0; i <10; i++ {
    e := email.NewEmail()
    e.From = "dj "
    e.To = []string{"935653229@qq.com"}
    e.Subject = "Awesome web"
    e.Text = []byte(fmt.Sprintf("Awesome Web %d", i+1))
    ch <- e
  }

  close(ch)
  wg.Wait()
}

上面程序中,我们创建 4 goroutine 共用一个连接池发送邮件,发送 10 封邮件后程序退出。为了等邮件都发送完成或失败,程序才退出,我们使用了 sync.WaitGroup

邮箱被轰炸了:

Go 每日一库之 email

由于使用了 goroutine,邮件顺序不能保证。

总结

本文介绍了如何使用 Go 程序发送邮件,程序代码都已经放在 GitHub 上 https://github.com/darjun/go-daily-lib/tree/master/email 。所有代码都通过测试,大家请放心食用~

大家如果发现好玩、好用的 Go 语言库,欢迎到 Go 每日一库 GitHub 上提交 issue:smile:

参考

  1. email GitHub: https://github.com/jordan-wright/email
  2. Go 每日一库 GitHub: https://github.com/darjun/go-daily-lib

我的博客

欢迎关注我的微信公众号【GoUpUp】,共同学习,一起进步~

Go 每日一库之 email

本文由博客一文多发平台 OpenWrite 发布!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 我们


推荐阅读
  • 本文由编程笔记小编整理,主要介绍了使用Junit和黄瓜进行自动化测试中步骤缺失的问题。文章首先介绍了使用cucumber和Junit创建Runner类的代码,然后详细说明了黄瓜功能中的步骤和Steps类的实现。本文对于需要使用Junit和黄瓜进行自动化测试的开发者具有一定的参考价值。摘要长度:187字。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • NotSupportedException无法将类型“System.DateTime”强制转换为类型“System.Object”
    本文介绍了在使用LINQ to Entities时出现的NotSupportedException异常,该异常是由于无法将类型“System.DateTime”强制转换为类型“System.Object”所导致的。同时还介绍了相关的错误信息和解决方法。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了在Spring 3.1中,数据源未能自动连接到@Configuration类的错误原因,并提供了解决方法。作者发现了错误的原因,并在代码中手动定义了PersistenceAnnotationBeanPostProcessor。作者删除了该定义后,问题得到解决。此外,作者还指出了默认的PersistenceAnnotationBeanPostProcessor的注册方式,并提供了自定义该bean定义的方法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
author-avatar
心语忆录_288
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有