邮件发送,附件太大怎么办 → 那就用分卷压缩吧

打印 上一主题 下一主题

主题 887|帖子 887|积分 2661

开心一刻

  昨晚,老婆辅导女儿写作业
  有一道形容妈妈的题,女儿写下了:我妈妈像一个暴躁的老虎
  老婆拿起题册轻轻敲了下女儿,生气到:有这么形容你妈的吗
  女儿:你看你现在
  老婆:我有那么暴躁吗,你就不能说我妈妈像一个公主,温柔大方漂亮?
  女儿:题目让我造句,没让我造谣!
  我:哈哈哈哈!

邮件发送

  基于 JavaMail 很容易实现邮件发送,例如基于 1.5.5 

  发送简单正文

  1. /**
  2. * 发送简单正文,并显示昵称
  3. * @param content 正文
  4. * @param to 收件人
  5. * @throws Exception
  6. */
  7. public static void sendMailNick(String content, String to) throws Exception {
  8.     //设置邮件会话参数
  9.     Properties props = new Properties();
  10.     //邮箱的发送服务器地址
  11.     props.setProperty("mail.smtp.host", MAIL_HOST);
  12.     props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
  13.     props.setProperty("mail.smtp.socketFactory.fallback", "false");
  14.     props.put("mail.smtp.ssl.enable", "true");
  15.     //邮箱发送服务器端口,这里设置为465端口
  16.     props.setProperty("mail.smtp.port", "465");
  17.     props.setProperty("mail.smtp.socketFactory.port", "465");
  18.     props.put("mail.smtp.auth", "true");
  19.     //获取到邮箱会话,利用匿名内部类的方式,将发送者邮箱用户名和密码授权给jvm
  20.     Session session = Session.getDefaultInstance(props, new Authenticator() {
  21.         @Override
  22.         protected PasswordAuthentication getPasswordAuthentication() {
  23.             return new PasswordAuthentication(MAIL_USER_NAME, MAIL_AUTH_CODE);
  24.         }
  25.     });
  26.     // 开启调试
  27.     session.setDebug(true);
  28.     // 创建传输对象
  29.     Transport trans = session.getTransport();
  30.     trans.connect(MAIL_HOST, "青石路", MAIL_AUTH_CODE);
  31.     // 创建邮件消息对象
  32.     Message message = new MimeMessage(session);
  33.     // 设置发件人信息(昵称:青石路)
  34.     message.setFrom(new InternetAddress(MAIL_USER_NAME, "青石路", "UTF-8"));
  35.     // 设置收件人信息
  36.     message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
  37.     // 设置正文
  38.     Multipart multipart = new MimeMultipart();
  39.     BodyPart contentPart = new MimeBodyPart();
  40.     contentPart.setContent(content, "text/html;charset=UTF-8");
  41.     multipart.addBodyPart(contentPart);
  42.     // 设置邮件主题和内容信息
  43.     message.setSubject("昵称测试");
  44.     message.setContent(multipart);
  45.     // 发送邮件
  46.     trans.sendMessage(message, message.getAllRecipients());
  47.     // 关闭传输
  48.     trans.close();
  49. }
复制代码
View Code
  需要注意的是,不同的邮箱的发件箱的端口会有不同,另外发件箱也可能是授权码而不是发件箱登陆密码,需要大家结合具体的邮箱服务器来设置
  不出意外的话,邮件发送成功后,收件箱会收到一封类似如下的邮件

  发送附件

  很多时候,我们发送邮件都会带附件
  实现也很简单
  1. /**
  2. * 发送邮件,带附件
  3. * @param content 正文
  4. * @param to 收件人
  5. * @param attachments 附件列表
  6. * @throws Exception
  7. */
  8. public static void sendMailNick(String content, String to, List<File> attachments) throws Exception {
  9.     //设置邮件会话参数
  10.     Properties props = new Properties();
  11.     //邮箱的发送服务器地址
  12.     props.setProperty("mail.smtp.host", MAIL_HOST);
  13.     props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
  14.     props.setProperty("mail.smtp.socketFactory.fallback", "false");
  15.     props.put("mail.smtp.ssl.enable", "true");
  16.     //邮箱发送服务器端口,这里设置为465端口
  17.     props.setProperty("mail.smtp.port", "465");
  18.     props.setProperty("mail.smtp.socketFactory.port", "465");
  19.     props.put("mail.smtp.auth", "true");
  20.     //获取到邮箱会话,利用匿名内部类的方式,将发送者邮箱用户名和密码授权给jvm
  21.     Session session = Session.getDefaultInstance(props, new Authenticator() {
  22.         @Override
  23.         protected PasswordAuthentication getPasswordAuthentication() {
  24.             return new PasswordAuthentication(MAIL_USER_NAME, MAIL_AUTH_CODE);
  25.         }
  26.     });
  27.     // 开启调试
  28.     session.setDebug(true);
  29.     // 创建传输对象
  30.     Transport trans = session.getTransport();
  31.     trans.connect(MAIL_HOST, "青石路", MAIL_AUTH_CODE);
  32.     // 创建邮件消息对象
  33.     Message message = new MimeMessage(session);
  34.     // 设置发件人信息(昵称:青石路)
  35.     message.setFrom(new InternetAddress(MAIL_USER_NAME, "青石路", "UTF-8"));
  36.     // 设置收件人信息
  37.     message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
  38.     // 设置正文
  39.     Multipart multipart = new MimeMultipart();
  40.     BodyPart contentPart = new MimeBodyPart();
  41.     contentPart.setContent(content, "text/html;charset=UTF-8");
  42.     multipart.addBodyPart(contentPart);
  43.     // 添加附件
  44.     if (Objects.nonNull(attachments) && !attachments.isEmpty()) {
  45.         for (File e : attachments) {
  46.             BodyPart attachmentBodyPart = new MimeBodyPart();
  47.             DataSource source = new FileDataSource(e);
  48.             attachmentBodyPart.setDataHandler(new DataHandler(source));
  49.             //MimeUtility.encodeWord可以避免文件名乱码
  50.             attachmentBodyPart.setFileName(MimeUtility.encodeWord(e.getName()));
  51.             multipart.addBodyPart(attachmentBodyPart);
  52.         }
  53.     }
  54.     // 设置邮件主题和内容信息
  55.     message.setSubject("昵称测试");
  56.     message.setContent(multipart);
  57.     // 发送邮件
  58.     trans.sendMessage(message, message.getAllRecipients());
  59.     // 关闭传输
  60.     trans.close();
  61. }
复制代码
View Code
  相比 发送简单正文 ,只多了一丢丢代码

  不出意外的话,邮件发送成功后,收件箱会收到一封类似如下的邮件

  附件过大

  但是各大电子邮箱对附件的大小都是由限制的,具体限制大小是多少,需要去看各大电子邮箱的官方说明
  例如我发送一个 200 多M的附件

  结果发送失败,异常信息如下
  1. java.net.SocketException: Connection reset by peer: socket write error
  2.     at java.net.SocketOutputStream.socketWrite0(Native Method)
  3.     at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
  4.     at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
  5.     at sun.security.ssl.OutputRecord.writeBuffer(OutputRecord.java:431)
  6.     at sun.security.ssl.OutputRecord.write(OutputRecord.java:417)
  7.     at sun.security.ssl.SSLSocketImpl.writeRecordInternal(SSLSocketImpl.java:876)
  8.     at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:847)
  9.     at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
  10.     at com.sun.mail.util.TraceOutputStream.write(TraceOutputStream.java:138)
  11.     at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
  12.     at java.io.BufferedOutputStream.write(BufferedOutputStream.java:126)
  13.     at com.sun.mail.util.CRLFOutputStream.write(CRLFOutputStream.java:84)
  14.     at com.sun.mail.smtp.SMTPOutputStream.write(SMTPOutputStream.java:87)
  15.     at com.sun.mail.util.CRLFOutputStream.write(CRLFOutputStream.java:75)
  16.     at com.sun.mail.util.BASE64EncoderStream.write(BASE64EncoderStream.java:140)
  17.     at javax.activation.DataHandler.writeTo(DataHandler.java:309)
  18.     at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1645)
  19.     at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:961)
  20.     at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:553)
  21.     at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:81)
  22.     at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:889)
  23.     at javax.activation.DataHandler.writeTo(DataHandler.java:317)
  24.     at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1645)
  25.     at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1850)
  26.     at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1241)
  27.     at com.qsl.MailTest.sendMailNick(MailTest.java:297)
  28.     at com.qsl.MailTest.main(MailTest.java:52)
复制代码
View Code
  碰到这种大文件,难道邮件就没法发送了吗?
  针对单个的大文件,作为一个附件确实发送不了
  如果将单个文件拆分成多个文件,再以多封邮件来发送,是不是可行了?
  此时大家可能会有疑问:非压缩文件可以按内容进行手动拆分,压缩文件怎么拆,特别是安装文件!
  我们觉得的不可能,不代表真的不可能,所以我们要多读书,拓展我们的知识面
分卷压缩

  关于概念,不做介绍,大家自行去搜索,重点给大家演示实现
  借助第三方组件: zip4j 

  很容易实现分卷压缩
  1. /**
  2. * 分卷压缩
  3. * @param sizeThreshold 分卷阈值,即多大进行一次分卷,单位:M
  4. * @param sourceFiles 源文件列表
  5. * @param destDirPath 目标目录,将源文件分卷到哪个目录
  6. * @param zipFileName 压缩文件名
  7. * @return 分卷文件列表
  8. * @throws Exception
  9. */
  10. public static List<File> splitVolumeCompressFiles(int sizeThreshold, List<File> sourceFiles, String destDirPath, String zipFileName) throws Exception {
  11.     List<File> zipFiles = new ArrayList<>();
  12.     if (Objects.isNull(sourceFiles) && sourceFiles.isEmpty()) {
  13.         return zipFiles;
  14.     }
  15.     // 目录不存在则创建
  16.     File dir = new File(destDirPath);
  17.     if (!dir.exists()) {
  18.         dir.mkdirs();
  19.     }
  20.     try (ZipFile zipFile = new ZipFile(destDirPath + File.separator + zipFileName + ".zip")) {
  21.         ZipParameters parameters = new ZipParameters();
  22.         parameters.setCompressionMethod(CompressionMethod.DEFLATE);
  23.         parameters.setCompressionLevel(CompressionLevel.NORMAL);
  24.         zipFile.createSplitZipFile(sourceFiles, parameters, true, sizeThreshold * 1024L * 1024L);
  25.         List<File> splitZipFiles = zipFile.getSplitZipFiles();
  26.         if (Objects.nonNull(splitZipFiles) && !splitZipFiles.isEmpty()) {
  27.             zipFiles = splitZipFiles;
  28.         }
  29.     }
  30.     return zipFiles;
  31. }
复制代码
View Code
  调用这个方法

  不出意外,在 D:/volume/ 目录下,得到如下文件

  我们直接解压 mysql-8.0.25-winx64.zip (其他的不用管),即可得到最初的源文件: mysql-8.0.25-winx64.zip 

邮件大附件

  相信此时,大家应该知道怎么处理了吧

  先进行分卷压缩,然后一封邮件发送一个附件,以多封邮件的方式将最初的源文件发送出去
  收到人收到附件后,将全部附件下载到同个目录下,然后进行解压即可得到最初的源文件

  其实就是将 分卷压缩 与 发送附件 结合起来即可

[code]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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

罪恶克星

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表