针对QQ邮箱发邮件限制的解决方案

由于QQ邮箱对于SMTP服务发送邮件做了限制,每分钟发送40封之后会被限制不能再发送,对于这样的限制又需要发送大量邮件的时候的解决方案如下

使用多个邮箱轮换使用进行发送

1、将使用的邮箱存储在一个统一的字符串变量中,将所有可使用的邮箱存储在一个字符串数组中(我的三个邮箱授权码相同,如果授权码不同,则建立一个授权码数组,和邮箱切换的解决方案同理)

全局变量(发邮件使用的邮箱)

private static String FPAMail="freeprogramming@qq.com";

可使用的邮箱数组

private static String FPAMailArray[]={"freeprogramming@qq.com","humorchen@vip.qq.com","3301633914@qq.com"};

2、将建立连接的代码封装到一个函数,将连接对象变为成员变量,全局化,即每次调用同一个变量,而变量的对象可能不相同(会变化)

连接相关对象变为全局变量

    private static Properties props;private static Session mailSession;private static MimeMessage message;private static Transport transport;

建立连接的函数

 private void init(){System.out.println("QQ邮件服务初始化开始:账号"+FPAMail);Date start=new Date();try {// 创建Properties 类用于记录邮箱的一些属性props = new Properties();// 表示SMTP发送邮件,必须进行身份验证props.put("mail.smtp.auth", "true");//此处填写SMTP服务器props.put("mail.smtp.host", "smtp.qq.com");//端口号,QQ邮箱给出了两个端口,但是另一个我一直使用不了,所以就给出这一个587props.put("mail.smtp.port", "587");// 此处填写你的账号props.put("mail.user",FPAMail );// 此处的密码就是前面说的16位STMP口令props.put("mail.password", FPAMailPwd);// 构建授权信息,用于进行SMTP进行身份验证Authenticator authenticator = new Authenticator() {protected PasswordAuthentication getPasswordAuthentication() {// 用户名、密码String userName = props.getProperty("mail.user");String password = props.getProperty("mail.password");return new PasswordAuthentication(userName, password);}};// 使用环境属性和授权信息,创建邮件会话mailSession = Session.getInstance(props, authenticator);// 创建邮件消息message = new MimeMessage(mailSession);// 设置发件人InternetAddress form = new InternetAddress(props.getProperty("mail.user"),NickName,"utf-8");message.setFrom(form);}catch (Exception e){e.printStackTrace();}Date end=new Date();System.out.println("QQ邮件发送会话初始化成功,耗时"+((end.getTime()-start.getTime()))+"毫秒");}

(不懂这几个对象是干嘛的百度)

3、设置每发送20封邮件切换一次邮箱,封装成函数

函数如下:

private void switchMail()
{int i=0;for (;i<FPAMailArray.length;i++)if (FPAMail.equals(FPAMailArray[i]))break;if (i+1==FPAMailArray.length)i=0;elsei++;FPAMail=FPAMailArray[i];init();
}

4、每次发送邮件的时候做判断(i%20==0)

public void sendToAllMember(String title,String html_content){System.out.println("发送邮件给所有会员");int i=1;for (String mail: MemberQQMailData.mails){System.out.println("正在处理第"+(i++)+"个"+"剩余"+(MemberQQMailData.mails.length-i+1)+"个,正在发送给:"+mail);sendQQMail(title,MailContentGenerator.QQMailNotice(title,html_content),mail);if (i%20==0)switchMail();}}

(MemberQQMailData.mails是一个字符串数组,存有所有会员的QQ邮箱)

效果图:每到第20封邮件就换一个邮箱进行发送,完美解决QQ邮箱发送限制问题

1.png

新版解决方案代码工具类

新版工具类代码
 

package cn.freeprogramming.util;import cn.hutool.core.date.StopWatch;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.locks.ReentrantLock;/*** QQ邮件发送工具** @Author:humorchen* @Date 2022/1/3 20:50*/
@Slf4j
public class QQMailUtil {/*** 超时时间*/private long TIMEOUT = 5000;/*** 重试次数*/private int RETRY_LIMIT = 10;/*** 使用第多少个账号(QQ每个账号限制频率了)*/private int accountIndex = 0;/*** 锁*/private ReentrantLock lock = new ReentrantLock(true);/*** 账号列表*/private List<QQMailAccount> accountList = new ArrayList<>();/*** 配置列表*/private List<Properties> propertiesList = new ArrayList<>();/*** 授权器*/private List<Authenticator> authenticatorList = new ArrayList<>();/*** 会话列表*/private List<Session> sessionList = new ArrayList<>();/*** 消息对象列表*/private List<MimeMessage> messageList = new ArrayList<>();/*** 发件人地址信息列表*/private List<InternetAddress> internetAddressArrayList = new ArrayList<>();/*** 发送器列表*/private List<Transport> transportList = new ArrayList<>();/*** 切换发件使用的邮箱下标*/private void changeUsingAccountIndex() {if (accountIndex == accountList.size() - 1) {accountIndex = 0;} else {accountIndex++;}}/*** 与QQ邮箱服务器建立连接** @throws Exception*/private void connect() throws Exception {QQMailAccount qqMailAccount = accountList.get(accountIndex);Properties properties = propertiesList.get(accountIndex);Authenticator authenticator = authenticatorList.get(accountIndex);Session session = Session.getInstance(properties, authenticator);MimeMessage message = new MimeMessage(session);InternetAddress senderInternetAddress = internetAddressArrayList.get(accountIndex);// 设置发件人InternetAddress fromInternetAddress = new InternetAddress(qqMailAccount.getAccount(), qqMailAccount.getNickname(), "utf-8");message.setFrom(fromInternetAddress);sessionList.set(accountIndex, session);messageList.set(accountIndex, message);Transport transport = session.getTransport(senderInternetAddress);transport.connect();log.info("isConnected {}", transport.isConnected());if (accountIndex < transportList.size()) {transportList.set(accountIndex, transport);} else {transportList.add(transport);}}/*** 发送邮件方法* 由线程池处理** @param title        邮件标题* @param html_content 邮件内容(支持html,图片等内容可能会被拦截,需要用户点击查看才能看到,或者让用户设置信任这个邮箱)* @param receiver     收件人邮箱*/@Asyncpublic void sendQQMail(String title, String html_content, String receiver) {StopWatch stopWatch = new StopWatch();try {lock.lock();log.info("发送邮件给 {} ,标题:{} ,\n内容:{}", receiver, title, html_content);stopWatch.start();QQMailAccount qqMailAccount = accountList.get(accountIndex);Transport transport = transportList.get(accountIndex);MimeMessage message = messageList.get(accountIndex);if (transport == null || !transport.isConnected()) {connect();}stopWatch.stop();log.info("连接花费 {}ms", stopWatch.getTotalTimeMillis());stopWatch.start();// 设置收件人的邮箱message.setRecipient(Message.RecipientType.TO, new InternetAddress(receiver));// 设置邮件标题message.setSubject(title, "utf-8");// 设置邮件的内容体message.setContent(html_content, "text/html;charset=UTF-8");try {//保存修改message.saveChanges();//发送邮件transport.sendMessage(message, new InternetAddress[]{new InternetAddress(receiver)});stopWatch.stop();log.info("使用邮箱:{} 发送成功,花费时间:{}ms", qqMailAccount.getAccount(), stopWatch.getTotalTimeMillis());} catch (Exception e) {//由于被腾讯方面因超时被关闭连接属于正常情况log.info("邮件发送失败,正在尝试和QQ邮件服务器重新建立链接");stopWatch.stop();stopWatch.start();boolean success = false;for (int i = 1; i <= RETRY_LIMIT; i++) {try {connect();log.info("使用邮箱:{} 成功建立链接", qqMailAccount.getAccount());transport = transportList.get(accountIndex);message = messageList.get(accountIndex);success = true;break;} catch (Exception ee) {changeUsingAccountIndex();qqMailAccount = accountList.get(accountIndex);log.info("链接建立失败,切换到邮箱:{} ,进行第 {} 次重试..." + qqMailAccount.getAccount(), i);}}if (success) {// 设置收件人的邮箱message.setRecipient(Message.RecipientType.TO, new InternetAddress(receiver));// 设置邮件标题message.setSubject(title, "utf-8");// 设置邮件的内容体message.setContent(html_content, "text/html;charset=UTF-8");message.saveChanges();transport.sendMessage(message, new InternetAddress[]{new InternetAddress(receiver)});stopWatch.stop();log.info("重建连接后使用邮箱:{} 发送成功,耗费时间:{}ms", qqMailAccount.getAccount(), stopWatch.getTotalTimeMillis());} else {log.error("链接多次尝试后无法建立,邮件发送失败!");return;}}} catch (Exception e) {log.error("sendQQMail", e);} finally {lock.unlock();if (stopWatch.isRunning()) {stopWatch.stop();}}}/*** 添加账号*/public void addAccount(String account, String authorizationCode, String nickname) {int oldAccountIndex = accountIndex;boolean addFinished = false;try {lock.lock();oldAccountIndex = accountIndex;accountIndex = accountList.size();QQMailAccount qqMailAccount = new QQMailAccount(account, authorizationCode, nickname);Properties properties = createProperties(qqMailAccount);Authenticator authenticator = createAuthenticator(qqMailAccount);// 使用环境属性和授权信息,创建邮件会话Session session = Session.getInstance(properties, authenticator);MimeMessage message = new MimeMessage(session);// 设置发件人InternetAddress internetAddress = new InternetAddress(account, nickname, "utf-8");message.setFrom(internetAddress);Transport transport = session.getTransport(new InternetAddress(qqMailAccount.getAccount()));transport.connect();accountList.add(qqMailAccount);propertiesList.add(properties);authenticatorList.add(authenticator);sessionList.add(session);transportList.add(transport);messageList.add(message);internetAddressArrayList.add(internetAddress);addFinished = true;} catch (Exception e) {//移除已经加入的if (addFinished) {accountList.remove(accountIndex);propertiesList.remove(accountIndex);authenticatorList.remove(accountIndex);sessionList.remove(accountIndex);transportList.remove(accountIndex);messageList.remove(accountIndex);internetAddressArrayList.remove(accountIndex);}log.error("addAccount", e);} finally {accountIndex = oldAccountIndex;lock.unlock();}}/*** 创建配置文件** @param qqMailAccount* @return*/private Properties createProperties(QQMailAccount qqMailAccount) {// 创建Properties 类用于记录邮箱的一些属性Properties properties = new Properties();// 表示SMTP发送邮件,必须进行身份验证properties.put("mail.smtp.auth", "true");//此处填写SMTP服务器properties.put("mail.smtp.host", "smtp.qq.com");//端口号,QQ邮箱给出了两个端口,但是另一个我一直使用不了,所以就给出这一个587properties.put("mail.smtp.port", "587");// 此处填写你的账号properties.put("mail.user", qqMailAccount.getAccount());// 此处的密码就是前面说的16位STMP口令properties.put("mail.password", qqMailAccount.getAuthorizationCode());//设置超时时间properties.put("mail.smtp.timeout", "" + TIMEOUT);return properties;}/*** 创建授权信息对象** @param qqMailAccount* @return*/private Authenticator createAuthenticator(QQMailAccount qqMailAccount) {// 构建授权信息,用于进行SMTP进行身份验证Authenticator authenticator = new Authenticator() {@Overrideprotected PasswordAuthentication getPasswordAuthentication() {// 用户名、密码String userName = qqMailAccount.getAccount();String password = qqMailAccount.getAuthorizationCode();return new PasswordAuthentication(userName, password);}};return authenticator;}private static class QQMailAccount {/*** 账号*/private String account;/*** 授权码*/private String authorizationCode;/*** 发送者昵称*/private String nickname;public QQMailAccount(String account, String authorizationCode, String nickname) {this.account = account;this.authorizationCode = authorizationCode;this.nickname = nickname;}public String getAccount() {return account;}public void setAccount(String account) {this.account = account;}public String getAuthorizationCode() {return authorizationCode;}public void setAuthorizationCode(String authorizationCode) {this.authorizationCode = authorizationCode;}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;QQMailAccount that = (QQMailAccount) o;return Objects.equals(account, that.account) && Objects.equals(authorizationCode, that.authorizationCode) && Objects.equals(nickname, that.nickname);}@Overridepublic int hashCode() {return Objects.hash(account, authorizationCode, nickname);}}
}

配置工具类对象到容器

package cn.freeprogramming.config;import cn.freeprogramming.util.QQMailUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** QQ邮件配置** @Author:humorchen* @Date 2022/1/3 21:54*/
@Configuration
public class QQMailConfig {//授权码,在QQ邮箱里设置private String authorizationCode = "hkkm123kasbjbf";private String nickname = "自由编程协会";@Beanpublic QQMailUtil qqMailUtil() {QQMailUtil qqMailUtil = new QQMailUtil();qqMailUtil.addAccount("freeprogramming@qq.com", authorizationCode, nickname);qqMailUtil.addAccount("freeprogramming@foxmail.com", authorizationCode, nickname);qqMailUtil.addAccount("357341307@qq.com", authorizationCode, nickname);return qqMailUtil;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/7671.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Outlook/Microsfot邮件配置:QQ邮箱/腾讯企业邮箱

记录下最终成功的记录 1.QQ邮箱配置 Step1 添加账户 Step 2 弹出的窗口中下拉至最下边&#xff1a;高级设置 Step 3 在弹出的窗口中选择Interner电子邮件 Step 4 填写配置信息&#xff0c;其中&#xff0c;不要忙着填写密码&#xff0c;其他的按照图中填写就可以了。 Step 5 进…

用telnet测试给qq邮箱发邮件,中途可能腾讯要你开启smtp服务器

注意下面绿色为你要在cmd端输入的内容 &#xff08;第1步&#xff09;telnet smtp.qq.com 25 220 smtp.qq.com Esmtp QQ Mail Server &#xff08;第2步&#xff09;helo 192.168.20.11//与qq服务器握手&#xff1a;这个192.168.20.11是你的主机的ip地址&#xff0c;可以通过…

[实战篇]关于QQ邮箱注册之测试用例

今天&#xff0c;我们来分析一个关于QQ邮箱注册的测试用例&#xff1a; 运用正交法&#xff0c;我们可以得到一个实验计划表&#xff0c;如下&#xff1a; 如图所示&#xff0c;注册页面共有三个输入框&#xff0c;正交表中呈现填写和不填写两种情况&#xff0c;而这三个输入框…

PHP中利用PHPMailer配合QQ邮箱实现发邮件

前言&#xff1a; 由于作业的需要&#xff0c;要实现给我们的网站用户发送邮件&#xff0c;于是就有了这篇博客。以下的内容是我结合网上的例子加上自己的实践的出来的。希望对大家有帮助。 PHPMailer的介绍&#xff1a; 优点&#xff1a; 可运行在任何平台之上支持SMTP验证…

[实战篇]关于QQ邮箱登录之测试用例

今天&#xff0c;我们来分析一个关于QQ邮箱登录模块的测试用例&#xff1a; 邮箱登录模块它就只有两个&#xff0c;一个是登录账号&#xff0c;一个是登录密码。在上一篇注册模块的文章中分析过&#xff0c;如果是一个输入框的话&#xff0c;你就直接对这一个输入框进行等价类…

phpmailer发送邮件(QQ企业邮箱和163邮箱)

注意&#xff1a;使用个人qq邮箱发送邮箱会被腾讯拦截发送失败 第一&#xff1a;163邮箱配置 1、登录163邮箱&#xff1a;https://email.163.com/ 2、在邮箱的设置中开启SMTP服务(设置->POP3/SMTP/IMAP->开启服务)&#xff0c;同时生成授权密码(发送邮件需要)&#xf…

腾讯邮箱网页版和foxmail邮箱邮件收取数量不一致

腾讯邮箱网页版无法导出邮件&#xff0c;所以下载了foxmail导出邮件&#xff0c;但是发现foxmail只能收取近一个月的邮箱 解决方法&#xff1a; 打开网页版的腾讯企业邮箱 点击 设置&#xff0c;点击 【收发信设置】 收取 【全部 】 邮件 再在foxmail收取即可&#xf…

腾讯往事:微信其实就是第四代 QQ 邮箱

【CSDN编者按】每天&#xff0c;很多CSDN公众号的用户都在通过微信公众号看文章&#xff0c;每天&#xff0c;我们几乎都在用微信。而其背后的公司腾讯&#xff0c;到今年已经二十一岁了。从最初马化腾的一个想法&#xff0c;到今天成长为举世瞩目的葳蕤&#xff08; wēi ru&a…

Python吴恩达机器学习作业 7 - K-means 和 PCA

编程作业 7 - K-means 和 PCA(主成分分析) 在本练习中&#xff0c;我们将实现K-means聚类&#xff0c;并使用它来压缩图像。我们将从一个简单的2D数据集开始&#xff0c;以了解K-means是如何工作的&#xff0c;然后我们将其应用于图像压缩。我们还将对主成分分析进行实验&…

吴恩达机器学习作业(七)K-means PCA ———python实现

K-means 参考资料&#xff1a;https://github.com/fengdu78/Coursera-ML-AndrewNg-Notes 先看数据&#xff1a; import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sb from scipy.io import loadmat data loadmat(data/ex7data2.m…

Games101,作业7(作业代码分析)

需要编写的函数 Vector3f Scene::castRay(const Ray &ray, int depth) const输入为一个光线&#xff0c;一个深度。 1.求出该光线与场景的交点 Intersection inter intersect(ray);该函数调用场景bvh类中的求交函数 Intersection Scene::intersect(const Ray &ray…

.net 平台下的数学库math.net(一)

Math.NET的目标是为提供一款自身包含清晰框架的符号运算和数学运算/科学运算&#xff0c;它是C#开发的开源类库。Math.NET含了一个支持线性代数的解析器&#xff0c;分析复杂微分&#xff0c;解方程等等功能。这个项目大部分采用的是MIT/X11开源软件协议。目前该组件主要分为以…

HIT-CSAPP 大作业

摘 要 以一个个简单的程序hello.c为样本&#xff0c;通过对它的从创建到结束的整个历程进行分析&#xff0c;分析研究hello程序在Linux下的P2P和020过程&#xff0c;进一步了解预处理、编译、汇编、链接和可执行文件执行过程中的进程管理、存储空间管理和I/O管理的原理&#…

吴恩达机器学习作业Python实现(七):K-means和PCA

目录 1 K-means聚类 1.1 K-means实现 1.1.1 找到最近的质心 1.1.2 计算质心 1.2 在示例数据集使用K-means算法 1.3 随机初始化 1.4 图像压缩 2 PCA 2.1 示例数据集 2.2 实现PCA 2.3 PCA降维 2.3.1 将数据投影在主成分上 2.3.2 重构数据 2.3.3 可视化 2.4 人脸…

ChatGPT辅导孩子作业有技巧

家长们&#xff0c;你是不是每天疲于奔命于工作和照顾孩子之间&#xff0c;还得抽空辅导孩子的作业&#xff1f;一边烦恼孩子作业多如牛毛&#xff0c;一边为自己的学习能力捉襟见肘&#xff1f;别担心&#xff0c;神秘的超级家长秘籍在此&#xff01;告别辅导孩子作业的痛苦&a…

百度地图api前端开发总结

1.this.map new BMapGL.Map(“mymap”); // 创建Map实例 2.this.map.centerAndZoom(new BMapGL.Point(116.404, 39.915), 5); // 初始化地图,设置中心点坐标和地图级别 3.this.map.enableScrollWheelZoom(true);//允许滚轮控制视口 4.var point new BMapGL.Point(116.404, 39…

全国各个省份市区县明细数据

全国总共有23个省、5个自治区、4个直辖市、2个特别行政区。 此数据包含省、市、区、县数据&#xff0c;共2886个。——更新于2023年6月10日 费了不少时间&#xff0c;暂时应该没有比我更全的了~~~细致到区县了 包括台湾省&#xff1a;台北市,新北市,桃园市,台中市,台南市,高…

【长白山旅游攻略】

《长白山旅游攻略》 一.游玩前的准备 1&#xff09;雪地冲锋衣羽绒服抓绒衫 2&#xff09;雪地冲锋裤抓绒裤 3&#xff09;厚围巾滑雪帽太阳镜手套&#xff0c;建议携带登山杖 4&#xff09;雪地登山鞋雪套 5&#xff09;高热零嘴白酒 6&#xff09;保湿面霜、唇膏 7&#xf…

白盒测试方法

一、白盒测试&#xff1a;又称结构测试、透明盒测试、逻辑驱动测试或基于代码的测试。 二、举例说明 1、逻辑覆盖法&#xff1a;是通过对程序逻辑结构的遍历实现程序的覆盖。 步骤一&#xff1a;通过程序逻辑结构画出流程图 步骤二&#xff1a;分析出哪些条件走哪些语句块 …

家乡的山-良岗山

戴云山东南延伸有余脉入漳&#xff0c;即为家乡长泰境内的邑山之首——良岗山。良岗山不仅巍峨雄伟&#xff0c;资源丰盛&#xff0c;而且历史悠久&#xff0c;人文景观众多&#xff0c;更以良岗圣王信仰泽被海峡两岸&#xff0c;蕴涵着两岸人民手足情深、血浓于水&#xff0c;…