开心一刻
昨晚,老婆辅导女儿写作业
有一道形容妈妈的题,女儿写下了:我妈妈像一个暴躁的老虎
老婆拿起题册轻轻敲了下女儿,生气到:有这么形容你妈的吗
女儿:你看你现在
老婆:我有那么暴躁吗,你就不能说我妈妈像一个公主,温柔大方漂亮?
女儿:题目让我造句,没让我造谣!
我:哈哈哈哈!
邮件发送
基于JavaMail很容易实现邮件发送,例如基于1.5.5
发送简单正文
/** * 发送简单正文,并显示昵称 * @param content 正文 * @param to 收件人 * @throws Exception */ public static void sendMailNick(String content, String to) throws Exception { //设置邮件会话参数 Properties props = new Properties(); //邮箱的发送服务器地址 props.setProperty("mail.smtp.host", MAIL_HOST); props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.setProperty("mail.smtp.socketFactory.fallback", "false"); props.put("mail.smtp.ssl.enable", "true"); //邮箱发送服务器端口,这里设置为465端口 props.setProperty("mail.smtp.port", "465"); props.setProperty("mail.smtp.socketFactory.port", "465"); props.put("mail.smtp.auth", "true"); //获取到邮箱会话,利用匿名内部类的方式,将发送者邮箱用户名和密码授权给jvm Session session = Session.getDefaultInstance(props, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(MAIL_USER_NAME, MAIL_AUTH_CODE); } }); // 开启调试 session.setDebug(true); // 创建传输对象 Transport trans = session.getTransport(); trans.connect(MAIL_HOST, "青石路", MAIL_AUTH_CODE); // 创建邮件消息对象 Message message = new MimeMessage(session); // 设置发件人信息(昵称:青石路) message.setFrom(new InternetAddress(MAIL_USER_NAME, "青石路", "UTF-8")); // 设置收件人信息 message.addRecipient(Message.RecipientType.TO, new InternetAddress(to)); // 设置正文 Multipart multipart = new MimeMultipart(); BodyPart contentPart = new MimeBodyPart(); contentPart.setContent(content, "text/html;charset=UTF-8"); multipart.addBodyPart(contentPart); // 设置邮件主题和内容信息 message.setSubject("昵称测试"); message.setContent(multipart); // 发送邮件 trans.sendMessage(message, message.getAllRecipients()); // 关闭传输 trans.close(); }
View Code
需要注意的是,不同的邮箱的发件箱的端口会有不同,另外发件箱也可能是授权码而不是发件箱登陆密码,需要大家结合具体的邮箱服务器来设置
不出意外的话,邮件发送成功后,收件箱会收到一封类似如下的邮件
发送附件
很多时候,我们发送邮件都会带附件
实现也很简单
/** * 发送邮件,带附件 * @param content 正文 * @param to 收件人 * @param attachments 附件列表 * @throws Exception */ public static void sendMailNick(String content, String to, List attachments) throws Exception { //设置邮件会话参数 Properties props = new Properties(); //邮箱的发送服务器地址 props.setProperty("mail.smtp.host", MAIL_HOST); props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.setProperty("mail.smtp.socketFactory.fallback", "false"); props.put("mail.smtp.ssl.enable", "true"); //邮箱发送服务器端口,这里设置为465端口 props.setProperty("mail.smtp.port", "465"); props.setProperty("mail.smtp.socketFactory.port", "465"); props.put("mail服务器托管网.smtp.auth", "true"); //获取到邮箱会话,利用匿名内部类的方式,将发送者邮箱用户名和密码授权给jvm Session session = Session.getDefaultInstance(props, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(MAIL_USER_NAME, MAIL_AUTH_CODE); } }); // 开启调试 session.setDebug(true); // 创建传输对象 Transport trans = session.getTransport(); trans.connect(MAIL_HOST, "青石路", MAIL_AUTH_CODE); // 创建邮件消息对象 Message message = new MimeMessage(session); // 设置发件人信息(昵称:青石路) message.setFrom(new InternetAddress(MAIL_USER_NAME, "青石路", "UTF-8")); // 设置收件人信息 message.addRecipient(Message.RecipientType.TO, new InternetAddress(to)); // 设置正文 Multipart multipart = new MimeMultipart(); BodyPart contentPart = new MimeBodyPart(); contentPart.setContent(content, "text/html;charset=UTF-8"); multipart.addBodyPart(contentPart); // 添加附件 if (Objects.nonNull(attachments) && !attachments.isEmpty()) { for (File e : attachments) { BodyPart attachmentBodyPart = new MimeBodyPart(); DataSource source = new FileDataSource(e); attachmentBodyPart.setDataHandler(new DataHandler(source)); //MimeUtility.encodeWord可以避免文件名乱码 attachmentBodyPart.setFileName(MimeUtility.encodeWord(e.getName())); multipart.addBodyPart(attachmentBodyPart); } } // 设置邮件主题和内容信息 message.setSubject("昵称测试"); message.setContent(multipart); // 发送邮件 trans.sendMessage(message, message.getAllRecipients()); // 关闭传输 trans.close(); }
View Code
相比发送简单正文,只多了一丢丢代码
不出意外的话,邮件发送成功后,收件箱会收到一封类似如下的邮件
附件过大
但是各大电子邮箱对附件的大小都是由限制的,具体限制大小是多少,需要去看各大电子邮箱的官方说明
例如我发送一个200多M的附件
结果发送失败,异常信息如下
java.net.SocketException: Connection reset by peer: socket write error at java.net.SocketOutputStream.socketWrite0(Native Method) at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109) at java.net.SocketOutputStream.write(SocketOutputStream.java:153) at sun.security.ssl.OutputRecord.writeBuffer(OutputRecord.java:431) at sun.security.ssl.OutputRecord.write(OutputRecord.java:417) at sun.security.ssl.SSLSocketImpl.writeRecordInternal(SSLSocketImpl.java:876) at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:847) at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123) at com.sun.mail.util.TraceOutputStream.write(TraceOutputStream.java:138) at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82) at java.io.BufferedOutputStream.write(BufferedOutputStream.java:126) at com.sun.mail.util.CRLFOutputStream.write(CRLFOutputStream.java:84) at com.sun.mail.smtp.SMTPOutputStream.write(SMTPOutputStream.java:87) at com.sun.mail.util.CRLFOutputStream.write(CRLFOutputStream.java:75) at com.sun.mail.util.BASE64EncoderStream.write(BASE64EncoderStream.java:140) at javax.activation.DataHandler.writeTo(DataHandler.java:309) at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1645) at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:961) at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:553) at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:81) at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:889) at javax.activation.DataHandler.writeTo(DataHandler.java:317) at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1645) at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1850) at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1241) at com.qsl.MailTest.sendMailNick(MailTest.java:297) at com.qsl.MailTest.main(MailTest.java:52)
View Code
碰到这种大文件,难道邮件就没法发送了吗?
针对单个的大文件,作为一个附件确实发送不了
如果将单个文件拆分成多个文件,再以多封邮件来发送,是不是可行了?
此时大家可能会有疑问:非压缩文件可以按内容进行手动拆分,压缩文件怎么拆,特别是安装文件!
我们觉得的不可能,不代表真的不可能,所以我们要多读书,拓展我们的知识面!
分卷压缩
关于概念,不做介绍,大家自行去搜索,重点给大家演示实现
借助第三方组件:zip4j
很容易实现分卷压缩
/** * 分卷压缩 * @param sizeThreshold 分卷阈值,即多大进行一次分卷,单位:M * @param sourceFiles 源文件列表 * @param destDirPath 目标目录,将源文件分卷到哪个目录 * @param zipFileName 压缩文件名 * @return 分卷文件列表 * @throws Exception */ public static List splitVolumeCompressFiles(int sizeThreshold, List sourceFiles, String destDirPath, String zipFileName) throws Exception { List zipFiles = new ArrayList(); if (Objects.isNull(sourceFiles) && sourceFiles.isEmpty()) { return zipFiles; } // 目录不存在则创建 File dir = new File(destDirPath); if (!dir.exists()) { dir.mkdirs(); } try (ZipFile zipFile = new ZipFile(destDirPath + File.separator + zipFileName + ".zip")) { ZipParameters parameters = new ZipParameters(); parameters.setCompressionMethod(CompressionMethod.DEFLATE); parameters.setCompressionLevel(CompressionLevel.NORMAL); zipFile.createSplitZipFile(sourceFiles, parameters, true, sizeThreshold * 1024L * 1024L); List splitZipFiles = zipFile.getSplitZipFiles(); if (Objects.nonNull(splitZipFiles) && !splitZipFiles.isEmpty()) { zipFiles = splitZipFiles; } } return zipFiles; }
View Code
调用这个方法
不出意外,在D:/volume/目录下,得到如下文件
我们直接解压mysql-8.0.25-winx64.zip(其他的不用管),即可得到最初的源文件:mysql-8.0.25-winx64.zip
邮件大附件
相信此时,大家应该知道怎么处理了吧
先进行分卷压缩,然后一封邮件发送一个附件,以多封邮件的方式将最初的源文件发送出去
收到人收到附件后,将全部附件下载到同个目录下,然后进行解压即可得到最初的源文件
其实就是将分卷压缩与发送附件结合起来即可
public static void main(String[] args) throws Exception { List attachments = new ArrayList(); attachments.add(new File("D:/下载/mysql-8.0.25-winx64.zip")); // 源文件(可以是多个)进行分卷压缩 List fileList = splitVolumeCompressFiles(20, attachments, "D:/volume", "mysql-8.0.25-winx64"); // 多封邮件进行发送,一封一个附件 for (int i=0; i) { // 可以异步发送 sendMailNick("邮件正文", MAIL_TO, Arrays.asList(fileList.get(i)), "大文件,分卷压缩(" + (i+1) + "/" + fileList.size() + ")"); } } /** * 分卷压缩 * @param sizeThreshold 分卷阈值,即多大进行一次分卷,单位:M * @param sourceFiles 源文件列表 * @param destDirPath 目标目录,将源文件分卷到哪个目录 * @param zipFileName 压缩文件名 * @return 分卷文件列表 * @throws Exception */ public static List splitVolumeCompressFiles(int sizeThreshold, List sourceFiles, String destDirPath, String zipFileName) throws Exception { List zipFiles = new ArrayList(); if (Objects.isNull(sourceFiles) && sourceFiles.isEmpty()) { return zipFiles; } // 目录不存在则创建 File dir = new File(destDirPath); if (!dir.exists()) { dir.mkdirs(); } try (ZipFile zipFile = new ZipFile(destDirPath + File.separator + zipFileName + ".zip")) { ZipParameters parameters = new ZipParameters(); parameters.setCompressionMethod(CompressionMethod.DEFLATE); parameters.setCompressionLevel(CompressionLevel.NORMAL); zipFile.createSplitZipFile(sourceFiles, parameters, true, sizeThreshold * 1024L * 1024L); List splitZipFiles = zipFile.getSplitZipFiles(); if (Objects.nonNull(splitZipFiles) && !splitZipFiles.isEmpty()) { zipFiles = splitZipFiles; } } return zipFiles; } /** * 发送邮件,带附件 * @param content 正文 * @param to 收件人 * @param attachments 附件列表 * @param title 邮件标题 * @throws Exception */ public static void sendMailNick(String content, String to, List attachments, String title) throws Exception { //设置邮件会话参数 Properties props = new Properties(); //邮箱的发送服务器地址 props.setProperty("mail.smtp.host", MAIL_HOST); props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.setProperty("mail.smtp.socketFacto服务器托管网ry.fallback", "false"); props.put("mail.smtp.ssl.enable", "true"); //邮箱发送服务器端口,这里设置为465端口 props.setProperty("mail.smtp.port", "465"); props.setProperty("mail.smtp.socketFactory.port", "465"); props.put("mail.smtp.auth", "true"); //获取到邮箱会话,利用匿名内部类的方式,将发送者邮箱用户名和密码授权给jvm Session session = Session.getDefaultInstance(props, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(MAIL_USER_NAME, MAIL_AUTH_CODE); } }); // 开启调试 session.setDebug(true); // 创建传输对象 Transport trans = session.getTransport(); trans.connect(MAIL_HOST, "青石路", MAIL_AUTH_CODE); // 创建邮件消息对象 Message message = new MimeMessage(session); // 设置发件人信息(昵称:青石路) message.setFrom(new InternetAddress(MAIL_USER_NAME, "青石路", "UTF-8")); // 设置收件人信息 message.addRecipient(Message.RecipientType.TO, new InternetAddress(to)); // 设置正文 Multipart multipart = new MimeMultipart(); BodyPart contentPart = new MimeBodyPart(); contentPart.setContent(content, "text/html;charset=UTF-8"); multipart.addBodyPart(contentPart); // 添加附件 if (Objects.nonNull(attachments) && !attachments.isEmpty()) { for (File e : attachments) { BodyPart attachmentBodyPart = new MimeBodyPart(); DataSource source = new FileDataSource(e); attachmentBodyPart.setDataHandler(new DataHandler(source)); //MimeUtility.encodeWord可以避免文件名乱码 attachmentBodyPart.setFileName(MimeUtility.encodeWord(e.getName())); multipart.addBodyPart(attachmentBodyPart); } } // 设置邮件主题和内容信息 message.setSubject(title); message.setContent(multipart); // 发送邮件 trans.sendMessage(message, message.getAllRecipients()); // 关闭传输 trans.close(); }
View Code
邮件发送完成后,收件人按如下方式处理即可得到源文件
总结
1、邮件附件不仅有大小限制,还有个数限制
2、文件皆可分卷,压缩文件与非压缩文件都可分卷
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
笔者在GitHub开了个 discussion 技术&开源&文章推荐,欢迎读者推荐贡献内容或者知识渠道 欢迎来到第 52 期的【视野修炼 – 技术周刊】,下面是本期的精选内容简介 强烈推荐 极速图片压缩器 use autojump in vsc…