观速讯丨QQ邮箱发邮件受限制怎么办?SMTP发送邮件限制的解决方案
由于QQ邮箱对于SMTP服务发送邮件做了限制,每分钟发送40封之后会被限制不能再发送,对于这样的限制又需要发送大量邮件的时候的解决方案如下
使用多个邮箱轮换使用进行发送
(资料图片仅供参考)
1、将使用的邮箱存储在一个统一的字符串变量中,将所有可使用的邮箱存储在一个字符串数组中(我的三个邮箱授权码相同,如果授权码不同,则建立一个授权码数组,和邮箱切换的解决方案同理)
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邮箱给出了两个端口,但是另一个我一直使用不了,所以就给出这一个587 props.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++) (fpamail.equals(fpamailarray[i]))="" break;="" if="" (i+1="=FPAMailArray.length)" i="0;" else="" i++;="" 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邮箱发送限制问题
新版解决方案代码工具类
新版工具类代码
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 */@Slf4jpublic class QQMailUtil { /** * 超时时间 */ private long TIMEOUT = 5000; /** * 重试次数 */ private int RETRY_LIMIT = 10; /** * 使用第多少个账号(QQ每个账号限制频率了) */ private int accountIndex = 0; /** * 锁 */ private ReentrantLock lock = new ReentrantLock(true); /** * 账号列表 */ private ListaccountList = new ArrayList<>(); /** * 配置列表 */ private ListpropertiesList = new ArrayList<>(); /** * 授权器 */ private ListauthenticatorList = new ArrayList<>(); /** * 会话列表 */ private ListsessionList = new ArrayList<>(); /** * 消息对象列表 */ private ListmessageList = new ArrayList<>(); /** * 发件人地址信息列表 */ private ListinternetAddressArrayList = new ArrayList<>(); /** * 发送器列表 */ private ListtransportList = 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 收件人邮箱 */ @Async public 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邮箱给出了两个端口,但是另一个我一直使用不了,所以就给出这一个587 properties.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() { @Override protected 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; } @Override public 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); } @Override public 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 */@Configurationpublic class QQMailConfig { //授权码,在QQ邮箱里设置 private String authorizationCode = "hkkm123kasbjbf"; private String nickname = "自由编程协会"; @Bean public 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; }}
标签: 发送邮件
相关推荐:
最新新闻:
- 推荐21个高质量图片网站 免费免版权值得收藏
- 什么是水冷机箱?水冷机箱和风冷机箱有什么区别?
- 如何解决显卡驱动无法正常安装?联想启天M6900介绍及驱动
- Office2003序列号有哪些?Office2003专业版序列号和注册码分享
- 如何屏蔽热点资讯广告提示框?热点资讯怎么彻底卸载?
- 360加速球怎样开启?加速球一直红色应该怎样解决?
- usb音箱没有声音?音响插电视上没声音怎么设置?
- 如何通过邮件群发工资条?outlook群发工资条失败咋办?
- pp助手怎么修复闪退?pp助手有什么用?
- sbsettings怎么设置?sbsettings设置的具体步骤
- Fc2视频打不开了怎么办?打开Fc2视频的步骤
- taobaoprotect.exe是什么进程?taobaoprotect.exe进程占用内存的解决方法
- java编程题:如何判断四个棋子连在一起?
- 出现此选项卡已经恢复是怎么回事?出现此选项卡已经恢复解决办法
- 全球时讯:免费下载国外视频的网站 你值得拥有
- 硬盘分区表都有什么修复方法?移动硬盘分区丢失后怎样找回?
- qq提取安装文件失败怎么办?压缩包无文件可提取咋回事?
- win10系统normal.dot在哪里?分享找到normal.dot文件的方法
- win7如何给文件设置密码?win7文件夹设置密码的具体步骤
- 如何做外链?做外链需要注意什么?
- 【体验】Xoom评测:比iPad重50克 屏幕倒更大?
- secondary logon服务是什么?开启secondary logon服务详细方法
- 每日快播:泥巴潭:《新龙族》免费卷土重来 拒绝“菜鸟玩家”
- 3dmark05怎么安装?3dmark05注册码分享
- Teracopy怎么样?Teracopy功能的及使用方法
- “东南亚小腾讯”大撤退,全面撤出欧洲市场
- 观速讯丨QQ邮箱发邮件受限制怎么办?SMTP发送邮件限制的解决方案
- 穿越时光隧道与古钓鱼城“面对面”|当前观察
- 天天热议:直降1000元 华硕 ProArt 创 16 2022 年终大促
- 游戏神U要来了 AMD居然定在情人节上市 全球观天下
- 每日简讯:最高6GHz睿频 英特尔13代酷睿i9-13900KS带来超凡体验
- 《霍格沃茨之遗》PC配置需求公布:推荐显卡1080 Ti
- FILA最好的时候已经过去?
- 当前资讯!《死亡空间:重制版》将采用2D地图 更易于使用!
- 黑鲨科技陨落,故事令人唏嘘_世界热文
- 《龙背上的农家》现已发售 Steam褒贬不一
- 【世界热闻】Q4利润增速一正一负,宁王让亿纬难望项背?| 见智研究
- 怪兽交配3D动作RPG新作《怪兽宇宙》1月上线
- 初代诞生26年 宝可梦种类现已超过1000种
- 三个月期美元Libor突破2008年金融危机期间高点 天天资讯
- 用上游戏本同款技术!联想小新Pro 16将支持独显直连
- 【环球速看料】ZOL科技早餐:英特尔6GHz睿频处理器上架,苹果新春电影《过五关》发布
- 节奏音游《节奏萌芽》2月1日全平台发售|世界快看
- 科幻Roguelike《巨人的肩膀》将于1月26日发行
- 比苹果MBP更轻 三星Galaxy Book 3 Ultra曝光
- 每日热文:木星卫星起降 NASA为创意买单
- 现代电车拥有横着走的蟹行模式
- CES总结:论性价比今年还得是买游戏本
- 苹果新设备可白嫖半年iCloud+ 2TB内存! 天天播报
- 环球今日讯!《三体》电视剧定档5小时 腾讯视频预约量突破200万
- 2022年Q4传统PC出货量下降28% PC市场热潮已结束
- 《GTA:三部曲-终极版》即将登陆Steam平台:环球即时看
- 国产新冠药研发,都到哪一步了?
- 全球快报:海南文旅大盘再现违建,被罚1.23亿
- 全球速读:十倍变焦超远摄 适马60-600mm F4.5-6.3 DG DN OS发布
- 当现实中的尸体,变成你在游戏中打的丧尸-世界热门
- 天天快消息!《天龙八部之乔峰传》25日韩国上映 甄子丹将录韩版跑男
- 动作片《灭世男孩》首曝剧照 山姆·雷米监制-全球观焦点
- 国产模拟经营游戏《学园构想家》限时试玩版1月16日上线
- 世界看点:越是善解人意,越不爱社交不想聊天?
- 女子上班第一天因已婚被辞 公司赔偿100元误工费
- 快消息!《生化危机4:重制版》中配PV公开 艾达王亮相
- 纵向卡牌构筑肉鸽游戏《铁轨与墓穴》 将于2023Q1发售
- 《隐秘的角落》公布新预告 1月18日登录Steam 每日观点
- B站游戏年度榜单:国产FPS+建造《重装前哨》新预告
- 《卧龙:苍天陨落》多人物中配CG首曝 吕布霸气登场
- B站公布2022年必玩游戏榜单:法环、战神5等上榜
- 小布助手四周年幕后:主动的人让AI更主动|快报
- 类魂动作《堕落之主》中配预告公布 暗黑骑士推翻邪神_天天速看料
- 当前观点:国风生存rogue新游《通神榜》 2月14日欢乐上线
- 《NBA 2K23》第四赛季场边报告 扎克·拉文绽放光芒_环球新要闻
- 环球今热点:《师父》公布粤配预告 即将登陆Steam
- 萌蟹类魂游戏《蟹蟹寻宝奇遇》发布最新中文宣传片 年内发售 微速讯
- 世界即时看!《绝世好武功》新预告公布 发售日期待定
- 想投资AIGC领域,怎样才能不被忽悠? 环球快播