廖雪峰Java13网络编程-2Email编程-1发送email

1.邮件发送

1.1传统邮件发送:

  • 传统的邮件是通过邮局投递,从一个邮局到另一个邮局,最终到达用户的邮箱。

1.2电子邮件发送:

  • 与传统邮件类似,它是从用户电脑的邮件软件(如outlook)发送到邮件服务器上,然后经过若干个邮件服务器的中转,到达对方邮件服务器上,收件方就可以用软件或浏览器来接收邮件。
  • MUA(邮件软件,Mail User Agent)——>MTA(邮件服务器,Mail Transfer Agent)——>MTA——>MDA(邮件投递代理,Mail Delivery Agent)<——MUA
  • 邮件一半到达MDA就不再动了,等收件人通过MUA或浏览器查看邮件即可
  • 从MUA发送到MTA使用的协议就是SMTP协议

1.3 SMTP协议:发送电子邮件的协议

  • Simple Mail Transport protocol:SMTP是一个建立在TCP之上的协议。
  • 标准端口:25
  • 加密端口:465/587。如果某个会话需要被加密的话,使用加密端口465/587

2 如何发送EMail:

  • 使用Java Mail API
  • 无需关心SMTP协议原理。

2.1 使用Java Mail API有三个部分

#    创建session
Session session = Session.getInstance(props,new Authenticator(){...});
#    创建message对象
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("from@email.com")); //发件人
message.setRecipient(Message.RecipientType.TO, new IntenetAddress("to@email.com")); //收件人
message.setSubject("RE:how to use JavaEmail","UTF-8"); //邮件主题
message.setText("blablabla...","UTF-8"); //邮件正文
#    发送邮件
Transport.send(message);

示例代码

package com.csj2018;

import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class SendQQMailUtil {

    public static void main(String[] args) throws AddressException,MessagingException {
        Properties properties = new Properties();
        properties.put("mail.transport.protocol", "smtp");// 连接协议
        properties.put("mail.smtp.host", "smtp.qq.com");// 主机名  网易替换为"smtp.126.com"
        properties.put("mail.smtp.port", 465);// 端口号
        properties.put("mail.smtp.auth", "true");
        properties.put("mail.smtp.ssl.enable", "true");// 设置是否使用ssl安全连接 ---一般都使用
//        properties.put("mail.debug", "true");// 设置是否显示debug信息 true 会在控制台显示相关信息,同session.setDebug(true);
        // 得到回话对象
        Session session = Session.getInstance(properties);
        session.setDebug(true);
        // 获取邮件对象
        Message message = new MimeMessage(session);
        // 设置发件人邮箱地址
        message.setFrom(new InternetAddress("123456789@qq.com"));
        // 设置收件人邮箱地址,多个收件人
        message.setRecipients(Message.RecipientType.TO, new InternetAddress[]{new InternetAddress("123456789@qq.com"),new InternetAddress("1234567890@qq.com")}); 
        //message.setRecipient(Message.RecipientType.TO, new InternetAddress("xxx@qq.com"));//一个收件人
        // 设置邮件标题
        message.setSubject("xmqtest");
        // 设置邮件内容
        message.setText("邮件内容邮件内容邮件内容xmqtest");
        // 得到邮差对象
        Transport transport = session.getTransport();
        // 连接自己的邮箱账户
        transport.connect("123456789@qq.com", "abcdefg");// 密码为QQ邮箱开通的stmp服务后得到的客户端授权码
        // 发送邮件
        transport.sendMessage(message, message.getAllRecipients());
        transport.close();
    }
}

2.2 新建maven工程

pom.xml导入依赖

<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4</version>
</dependency>

注意:不要导错依赖。详细请参考

        <!-- https://mvnrepository.com/artifact/javax.mail/javax.mail-api -->
        <!--导入javax.mail-api,运行时会提示Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/mail/util/MailLogger
-->
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>javax.mail-api</artifactId>
            <version>1.6.2</version>
        </dependency>

2.3 发送一封文本邮件

package com.email;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.security.MessageDigest;
import java.util.Properties;

public class SendMail {
    final String smtpHost;
    final String username;
    final String password;
    final boolean debug;
    public SendMail(String smtpHost,String username,String password){
        this.smtpHost = smtpHost;
        this.username = username;
        this.password = password;
        this.debug = true;
    }
    public static void main(String[] args) throws Exception{
        SendMail sender = new SendMail("smtp.qq.com","123456789@qq.com","abcdefg");
        Session session = sender.createSSLSession();
        Message message = createTextMessage(session,"123456789@qq.com","123456789@126.com","标题吗","Hello,这是一封Javamail测试邮件");
        Transport.send(message);
    }
    //创建一个加密的session对象
    private Session createSSLSession(){
        Properties props = new Properties();
        props.put("mail.transport.protocol","smtp");
        props.put("mail.smtp.host",this.smtpHost);//SMTP主机名
        props.put("mail.smtp.port",465);//主机端口号
        props.put("mail.smtp.auth","true");//是否需要用户认证
        //启动SSL
        props.put("mail.smtp.socketFactory.class","javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.socketFactory.port","465");
        Session session = Session.getInstance(props, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(SendMail.this.username,SendMail.this.password);
            }
        });
        session.setDebug(this.debug);//显示调试信息
        return session;
    }
    private static Message createTextMessage(Session session,String from,String to,String subject,String body) throws MessagingException {
        MimeMessage message= new MimeMessage(session);
        message.setFrom(new InternetAddress(from));
        message.setRecipient(Message.RecipientType.TO,new InternetAddress(to));
        message.setSubject(subject,"UTF-8");
        message.setText(body,"UTF-8");
        return message;
    }
}

2.4发送一个HTML格式的邮件

package com.email;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class SendMailWithHtml {
    public static void main(String[] args) throws Exception{
        SendMail sendMail = new SendMail("smtp.qq.com","123456789@qq.com","abcdefg");
        Session session = sendMail.createSSLSession();
        Message message = createHtmlMessage(session,"123456789@qq.com","123456789@126.com","这是一封html的邮件","\n" +
                "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" +
                "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
                "\n" +
                "<head>\n" +
                "\n" +
                "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n" +
                "<meta http-equiv=\"Cache-Control\" content=\"no-transform\" />\n" +
                "<title>剧烈咳嗽就是肺癌?肺癌的这些症状也不可忽视 - 家庭医生在线肿瘤频道</title>\n" +
                "<meta name=\"keywords\" content=\"剧烈咳嗽,肺癌,肺癌的症状\" />\n" +
                "<meta name=\"description\" content=\"肺癌,一个发病率极其高的癌症,由于目前环境污染日渐严重,导致越来越多的人肺部受到感染而出现病变,导致肺癌的出现,生活中有很多因为肺癌而丧失性命的人。也正是因为如此让很多人对于肺癌都比较重视,对于肺癌也有做相关的了解,而大多数人因为过于谨慎,在身体出现一些成风吹草动的时候就认为是肺癌,特别是在出现剧烈咳嗽的时候,其实出现剧烈咳嗽也并不完全是肺癌发生。\" />\n" +
                "<script type=\"text/javascript\">\n" +
                "CUSTOMER.setCus([\"channel:cancer\",\"level:page\"]);\n" +
                "</script>\n" +
                "</head>\n" +
                "<body>\n" +
                "\t<div class=\"article-titile\">\n" +
                "\t\t<h1>剧烈咳嗽就是肺癌?肺癌的这些症状也不可忽视</h1></div>\n" +
                "<!--头部模块开始--> \n" +
                "<div id=\"viewContent\" class=\"viewContent\"> <p style=\"text-indent:2em;text-align:left;\">肺癌,一个发病率极其高的,由于目前环境污染日渐严重,导致越来越多的人肺部受到而出现病变,导致肺癌的出现,生活中有很多因为肺癌而丧失性命的人。也正是因为如此让很多人对于肺癌都比较重视,对于肺癌也有做相关的了解,而大多数人因为过于谨慎,在身体出现一些成风吹草动的时候就认为是肺癌,特别是在出现剧烈咳嗽的时候,其实出现剧烈咳嗽也并不完全是肺癌发生。</p>\n" +
                "\t\t\t</div>\n" +
                "</body>\n" +
                "</html>");
        Transport.send(message);
    }
    static Message createHtmlMessage(Session session,String from,String to,String subject,String body) throws MessagingException{
        MimeMessage message = new MimeMessage(session);
        message.setFrom(new InternetAddress(from));
        message.setRecipient(Message.RecipientType.TO,new InternetAddress(to));
        message.setSubject(subject,"UTF-8");
        message.setText(body,"UTF-8","html");
        return message;
    }
}
### 2.5发送带附件的邮件 ```#java package com.email;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.io.
;

public class SendMailWithAttachment {
public static void main(String[] args) throws Exception{
SendMail sender = new SendMail("smtp.qq.com","123456678@qq.com","abcdefghjik");
Session session = sender.createSSLSession();
//创建一个带附件的邮件
Message message = createMessageWithAttachment(session,"123456678@qq.com","红米note5图片","为什么成功了","/src/main/resources/1.jpg","123456789@qq.com","987654321@qq.com","123456789@126.com");
Transport.send(message);
File f = new File(".");
System.out.println(f.getCanonicalFile());
File nf = new File(f.getCanonicalFile()+"/src/main/resources/1.jpg");
if(nf.exists()){
System.out.println(nf+"存在");
}else{
System.out.println(nf+"不存在");
}

}
static Message createMessageWithAttachment(Session session, String from, String subject,String body, String filename, String... to) throws MessagingException,IOException {
    //本质上还是一个MimeMessage对象,但不能通过setText设置正文,需要使用MimeMultipart
    MimeMessage message = new MimeMessage(session);
    message.setFrom(new InternetAddress(from));
    for(String s:to){
        message.setRecipient(Message.RecipientType.TO,new InternetAddress(s));
    }

    message.setSubject(subject);
    //通过Multipart将内容分为2部分
    Multipart multipart = new MimeMultipart();
    //text
    BodyPart textpart = new MimeBodyPart();
    textpart.setContent(body,"text/html;charset=utf-8");//body表示邮件正文
    multipart.addBodyPart(textpart);
    //再次创建一个MimeBodyPart上传附件
    BodyPart imagePart = new MimeBodyPart();
    imagePart.setFileName(filename);
    DataHandler dh1 = new DataHandler(new FileDataSource(new File(".").getCanonicalPath()+filename));
    imagePart.setDataHandler(dh1);//如何获取附件的数据
    multipart.addBodyPart(imagePart);

    message.setContent(multipart);
    return message;
}

}

<h1 style="color:blue">使用输入流发送附件</h1>
<p style="color:red">确保图片在resource目录下</p>

```#java
package com.email;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class SendMailWithAttachment {
    public static void main(String[] args) throws Exception{
        SendMail sender = new SendMail("smtp.qq.com","123456789@qq.com","abcdefghjkik");
        Session session = sender.createSSLSession();
        //创建一个输入流
        try(InputStream input = SendMailWithAttachment.class.getResourceAsStream("/1.jpg")){
            //创建一个带附件的邮件
            Message message = createMessageWithAttachment(session,"123456789@qq.com","红米note5图片","为什么成功了","1.jpg",input,"123456789@qq.com","987654321@qq.com","123456789@126.com");
            Transport.send(message);
        }
    }
    static Message createMessageWithAttachment(Session session, String from, String subject,String body, String filename,InputStream input, String... to) throws MessagingException,IOException {
        //本质上还是一个MimeMessage对象,但不能通过setText设置正文,需要使用MimeMultipart
        MimeMessage message = new MimeMessage(session);
        message.setFrom(new InternetAddress(from));
        for(String s:to){
            message.setRecipient(Message.RecipientType.TO,new InternetAddress(s));
        }

        message.setSubject(subject);
        //通过Multipart将内容分为2部分
        Multipart multipart = new MimeMultipart();
        //text
        BodyPart textpart = new MimeBodyPart();
        textpart.setContent(body,"text/html;charset=utf-8");//body表示邮件正文
        multipart.addBodyPart(textpart);
        //再次创建一个MimeBodyPart上传附件
        BodyPart imagePart = new MimeBodyPart();
        imagePart.setFileName(filename);
        imagePart.setDataHandler(new DataHandler(new ByteArrayDataSource(input,"Application/octet-stream")));
        multipart.addBodyPart(imagePart);
        message.setContent(multipart);
        return message;
    }
}

2.6如何把附件嵌入到正文中

package com.csj2018;

import javax.activation.DataHandler;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
import java.io.InputStream;

public class SendMailWithInnerImage {
    public static void main(String[] args) throws Exception{
        SendMail sender = new SendMail("smtp.qq.com", "815379479@qq.com", "oovtbkpfvfzobdag");
        Session session = sender.createSSLSession();
        try(InputStream input = SendMailWithInnerImage.class.getResourceAsStream("/RedmiNote5-1.png")){
            Message message = createMessageWithInnerImage(session,"815379479@qq.com","chenshanju01@126.com","带图片测试","<h1><hello/h1><p><img src=\"cid:img01\" ></p><p>这是一封带图片的测试邮件</p>","1.png",input);
            Transport.send(message);
        }
    }
    static Message createMessageWithInnerImage(Session session, String from, String to, String subject, String body, String filename, InputStream input) throws Exception{
        MimeMessage message = new MimeMessage(session);
        message.setFrom(new InternetAddress(from));
        message.setRecipient(Message.RecipientType.TO,new InternetAddress(to));
        message.setSubject(subject,"UTF-8");
        Multipart multipart = new MimeMultipart();
        BodyPart textpart = new MimeBodyPart();
        textpart.setContent(body,"text/html;charset=utf-8");
        multipart.addBodyPart(textpart);

        BodyPart imagepart = new MimeBodyPart();
        imagepart.setFileName(filename);
        imagepart.setDataHandler(new DataHandler(new ByteArrayDataSource(input,"application/x-png")));
        //对一个图片内容设置Content-ID,就可以在邮件中引用它,引用方式是<img src="cid:img01">
        imagepart.setHeader("Content-ID","<img01>");
        multipart.addBodyPart(imagepart);
        message.setContent(multipart);
        return message;
    }
}

content-type类型对应表:http://tool.oschina.net/commons/

3.总结

使用JavaMail API发送邮件本质上是一个MUA软件,类似outlook
Java发送Email:

  • 用Maven引入javamail依赖
  • 确定SMTP服务器信息:域名/端口/使用明文/SSL/TLS
  • 调用相关API发送Email(无需关心底层TCP Socket连接)
  • 设置debug模式可以查看通信详细内容
posted on 2019-07-15 05:20  singleSpace  阅读(369)  评论(0编辑  收藏  举报