Scala发邮件(带附件,无论是本地文件和hdfs文件或df或rdd)

@羲凡——只为了更好的活着

Scala发邮件(带附件,无论是本地文件和hdfs文件或df或rdd)

在有些spark任务执行完后需要通知我们该任务已经执行结束,发邮件到某个邮箱是最直接的方式。那如何用scala发邮件呢,我在网上没有找到一个案例,我研究了一天终于被我解决了。下面字节上代码:

import java.io.File

import com.typesafe.config.ConfigFactory
import org.apache.spark.sql.SparkSession
import play.api.libs.mailer._

object TestSendMail {
  def main(args: Array[String]): Unit = {
    val spark = SparkSession.builder()
      .appName("TestSendMail")
      .master("local[*]")
      .getOrCreate()
    // 将hdfs上的文件生成rdd
    val rdd = spark.sparkContext.textFile("/aarontest/data/wc.txt")

    val subject = "羲凡-Scala发邮件" //邮件主题
    val from = "aaa@qq.com" //邮件发送地址
    val to = Seq("bbb@qq.com", "ccc@163.com") //邮件接收地址
    //val bodyText = Option("==========scala发邮件成功啦!!!==========")
    val bodyHtml = Option(
      """
        |<html>
        |<body>
        |<h1 align="center">Scala发邮件成功啦</h1>
        |<h2 align="center">Get busy living, Or get busy dying</h2>
        |<h3 align="center">Get busy living, Or get busy dying</h3>
        |</body>
        |</html>
      """.stripMargin)
    val charset = Option("utf-8") // 字符编码 默认utf-8

    // 以本地文件为附件相关参数
    val name = "以本地文件为附件"
    val file = new File("D:\\AaronProject\\SparkTest227\\data\\wc.txt")
    val attachment: Attachment = AttachmentFile(name, file)

    // 以hdfs文件或rdd或df为附件相关参数
    val name2 = "以hdfs文件为附件"
    val data: Array[Byte] = rdd.collect().mkString("\n").getBytes()
    val mimetype = "text/plain" // 根据文件类型选择MimeTypes对应的值
    val attachment2: Attachment = AttachmentData(name2, data, mimetype)

    // 将两个附件生成一个seq序列
    val attachments: Seq[Attachment] = Seq(attachment, attachment2)
    // 生成邮件
    val email = Email(subject,from,to,None,bodyHtml,charset,attachments = attachments)

    // STMP服务参数
    val host = "smtp.qq.com" // STMP服务地址
    val port = 587 // STMP服务端口号
    val user = Option("aaa@qq.com") // STMP服务用户邮箱
    val password = Option("rjnsjyalufzwbebd") // STMP服务邮箱密码
    val timeout = Option(10000) //setSocketTimeout 默认60s
    val connectionTimeout = Option(10000) //setSocketConnectionTimeout 默认60s
    // STMP服务SMTPConfiguration
    val configuration: SMTPConfiguration = new SMTPConfiguration(
      host, port, false, false, false,
      user, password, false, timeout,
      connectionTimeout, ConfigFactory.empty(), false)
    val mailer: SMTPMailer = new SMTPMailer(configuration)

    // 发送邮件
    mailer.send(email)
    println("==========scala发邮件成功啦!!!==========")
    spark.stop()
  }
}

结果展示:
在这里插入图片描述

注意事项

1.pom.xml 文件中添加依赖,依赖的版本不同代码会有略微的变化(我亲测5.0.0的版本和7.0.0的就不一样)

<dependency>
	<groupId>com.typesafe.play</groupId>
	<artifactId>play-mailer_2.11</artifactId>
	<version>7.0.0</version>
</dependency>

2.如果用QQ邮箱发邮件给别的邮箱,需要先开启QQ邮箱的SMTP服务且邮箱的登录密码换成你邮箱的授权码。什么是授权码,它又是如何设置?官网:https://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256 。两者缺一不可,否则会报如下错误

Exception in thread "main" org.apache.commons.mail.EmailException: Sending the email to the following server failed : smtp.qq.com:587
	at org.apache.commons.mail.Email.sendMimeMessage(Email.java:1469)
	at org.apache.commons.mail.Email.send(Email.java:1496)
	at play.api.libs.mailer.SMTPMailer$$anon$1.send(SMTPMailer.scala:14)
	at play.api.libs.mailer.CommonsMailer.send(CommonsMailer.scala:23)
	at play.api.libs.mailer.SMTPMailer.send(SMTPMailer.scala:24)
	at scalatest.TestSendMail$.main(TestSendMail.scala:39)
	at scalatest.TestSendMail.main(TestSendMail.scala)
Caused by: javax.mail.AuthenticationFailedException: 535 Error: ÇëʹÓÃÊÚȨÂëµÇ¼¡£ÏêÇéÇë¿´: http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256

	at com.sun.mail.smtp.SMTPTransport$Authenticator.authenticate(SMTPTransport.java:932)
	at com.sun.mail.smtp.SMTPTransport.authenticate(SMTPTransport.java:843)
	at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:748)
	at javax.mail.Service.connect(Service.java:388)
	at javax.mail.Service.connect(Service.java:246)
	at javax.mail.Service.connect(Service.java:195)
	at javax.mail.Transport.send0(Transport.java:254)
	at javax.mail.Transport.send(Transport.java:124)
	at org.apache.commons.mail.Email.sendMimeMessage(Email.java:1459)
	... 6 more

3.如果邮件发送给多个邮箱,每个邮箱间用逗号分隔,见如上代码
4.如果bodyText参数和bodyHtml参数同事有,则只会显示bodyHtml中的内容,一般情况下这两个参数也只会用一个,另一个用None,见如上代码
5.发邮件添加本地文件和非本地文件作为附件的样例类不同,分别是AttachmentFile和AttachmentData。如果直接用AttachmentFile来添加hdfs上文件作附件,报错找不到文件,具体如下

Exception in thread "main" org.apache.commons.mail.EmailException: Cannot attach file "\aarontest\data\wc.txt"
	at org.apache.commons.mail.MultiPartEmail.attach(MultiPartEmail.java:333)
	at play.api.libs.mailer.CommonsMailer.play$api$libs$mailer$CommonsMailer$$handleAttachmentFile(CommonsMailer.scala:154)
	at play.api.libs.mailer.CommonsMailer$$anonfun$createEmail$10.apply(CommonsMailer.scala:43)
	at play.api.libs.mailer.CommonsMailer$$anonfun$createEmail$10.apply(CommonsMailer.scala:39)
	at scala.collection.immutable.List.foreach(List.scala:392)
	at play.api.libs.mailer.CommonsMailer.createEmail(CommonsMailer.scala:39)
	at play.api.libs.mailer.CommonsMailer.send(CommonsMailer.scala:23)
	at play.api.libs.mailer.SMTPMailer.send(SMTPMailer.scala:24)
	at scalatest.TestSendMail$.main(TestSendMail.scala:49)
	at scalatest.TestSendMail.main(TestSendMail.scala)
Caused by: java.io.IOException: "\aarontest\data\wc.txt" does not exist
	at org.apache.commons.mail.MultiPartEmail.attach(MultiPartEmail.java:322)
	... 9 more

6.以非本地文件为附件时,一定要将AttachmentData中data参数变成Array[Byte]格式。否则会报错Exception in thread "main" java.lang.NumberFormatException。如果出现这个错误则说明你的data的数据类型不对或转换的方式出错了。比如我将data的值改成 rdd.collect().map(_.toByte) ,虽然data的数据类型变成了Array[Byte],但还是会报如上的错误,因为转换的方式不对。
7.以非本地文件为附件时,AttachmentData中mimetype参数要根据自己的需要设置,常见的MIME类型如下:

普通文本 text/plain 
超文本标记语言文本 text/html 
JPEG图形 image/jpeg 
csv文件 text/csv
xml文件 application/xml

如果想了解更多的MIME类型可参考 https://blog.csdn.net/qq_19916577/article/details/46502761

====================================================================

@羲凡——只为了更好的活着

若对博客中有任何问题,欢迎留言交流

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 22
    评论
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值