最近由于注册用户的增多,qq企业邮箱发送邮件会被封禁账号导致注册后面的用户收不到周总结,所以紧急开发了一套多账号,多服务器发送邮件的程序。

大概的设计思路如下:

JavaMailSender 多个收件人 java批量发送邮件_json

1.服务器可以无限扩展,但由于qq企业邮箱是限定域名,所以要想多服务器还得有多域名,多账号也不行。

2.最核心的代码是FIFO分配指定长度的邮件列表这一步,通过java线程同步Queue实现。

3.发送失败的要加到重试队列继续发送。

4.经测试每分钟发一封邮件,qq企业邮箱最大可以发送7000封邮件,这样最代码2个账号[email protected]和[email protected]就可以发送到15000个邮件,该方案绝对是性价比超高的,目前市面上每封邮件1分钱,那15000也得150元人民币,如果你每周呢?

5.可以指定某个用户id来只发送某个范围的邮件列表

6.可以指定clear参数来清空所有邮件列表,不过该参数慎用,避免多发送邮件。

下面分享下核心代码,有思路和代码做参考,我想大家肯定可以自己搭建起来了:

分配邮件端核心java代码:

private final static Map> map = new HashMap>();
// 申请发邮件的邮箱地址,每次根据mailTaskCount配置来取个数
public @ResponseBody
JSONObject apply_mails(
@PathVariable("id") Long id,
@RequestParam(value = "start_date", required = false) String startDate,
@RequestParam(value = "end_date", required = false) String endDate,
@RequestParam(value = "clear", required = false) String clear,
@RequestParam(value = "user_id", required = false) Long user_id)
throws IOException, TemplateException {
JSONObject json = new JSONObject();
String error = "";
if (StringUtils.isBlank(startDate) || StringUtils.isBlank(endDate)) {
error = "参数非法,startDate和endDate";
json.put("error", error);
return json;
}
final Task task = taskService.findOneById(id);
if (task.getType() != ModuleConstants.TASK_TYPE_WEEK_SUMMARY) {
error = "任务" + id + "不是周总结";
json.put("error", error);
return json;
}
Queue allUsers = null;
List users = new ArrayList();
synchronized (map) {//注意线程安全
if (StringUtils.isNotBlank(clear)) {// clear
map.put(id, null);
error = "任务清空成功";
json.put("error", error);
return json;
}
allUsers = map.get(id);
if (allUsers == null) {
allUsers = new LinkedList();
if (user_id == null) {
user_id = 0l;
}
Page page = userService
.findAllReceiveMailUsersGreaterThanId(user_id, 1,
Integer.MAX_VALUE);
allUsers.addAll(page.getContent());
map.put(id, allUsers);
}
int size = allUsers.size();
if (size == 0) {
error = "任务" + id + "执行完毕!";
json.put("error", error);
return json;
}
int i = 0;
while (i < mailTaskCount) {
User _user = allUsers.poll();
if (_user == null) {
break;
}
users.add(_user);
i++;
}
}
File templateFile = new File(deployPath + "/apply_week_summary_" + id
+ ".html");
String templdate = "";
if (templateFile.exists()) {
templdate = FileUtils.readFileToString(templateFile, "utf-8");
} else {
List weekSummaryShareIds = findIds(startDate, endDate);
ModelMap model = new ModelMap();
Collection weekSummaryShares = projectService
.findAllByIds(weekSummaryShareIds);
Configuration configuration = freemarkerConfig.getConfiguration();
configuration.setDirectoryForTemplateLoading(new File(deployPath
+ "/WEB-INF/template/"));
Template template = configuration
.getTemplate("apply_week_summary.htm");
Page weekRankUsers = rankService.findAllByType(
ModuleConstants.RANK_TYPE_USER_CONTRIBUTE_WEEK,
ParamConstants.DEFAULT_PAGE,
ParamConstants.DEFAULT_TOP_LESS_COUNT,
ModuleConstants.RANKSORT);
model.put("weekRankUsers", weekRankUsers);
Page monthRankUsers = rankService.findAllByType(
ModuleConstants.RANK_TYPE_USER_CONTRIBUTE_MONTH,
ParamConstants.DEFAULT_PAGE,
ParamConstants.DEFAULT_TOP_LESS_COUNT,
ModuleConstants.RANKSORT);
model.put("monthRankUsers", monthRankUsers);
model.put("task", task);
model.put("weekSummaryShares", weekSummaryShares);
Sort sort = new Sort(Direction.DESC, "secondSort");
Page downloadProjects = projectService.findAllByType(
ModuleConstants.PROJECT_TYPE_SHARE_CODE, 1,
ParamConstants.DEFAULT_TOP_COUNT, sort);
model.put("downloadProjects", downloadProjects);
sort = new Sort(Direction.DESC, "thirdSort");
Page commentProjects = projectService.findAllByType(
ModuleConstants.PROJECT_TYPE_SHARE_CODE, 1,
ParamConstants.DEFAULT_TOP_COUNT, sort);
model.put("commentProjects", commentProjects);
StringWriter stringWriter = new StringWriter();
stringWriter.flush();
stringWriter.close();
template.process(model, stringWriter);
FileUtils.writeStringToFile(templateFile, stringWriter.toString(),
"utf-8");
templdate = stringWriter.toString();
}
json.put("template", templdate);
JSONArray usersJson = new JSONArray();
for (User user : users) {
JSONObject userJson = new JSONObject();
userJson.put("id", user.getId());
userJson.put("uuid", user.getUuid());
String code = Security.encryptUnsubscribeWeeklyEmail(user.getId()
+ "_" + new Date().getTime());
userJson.put("unsubscribe_weekly_email_code", code);
userJson.put("email", user.getEmail());
usersJson.add(userJson);
}
json.put("users", usersJson);
json.put("error", error);
json.put("title", task.getTitle());
return json;
}
发送邮件端核心java代码:public static void main(String[] args) {
if (args.length < 3) {
System.out
.println("需要3个参数:\n第一个是task id\n第二个是开始时间,如:2014-05-05\n第三个是结束时间,如:2014-05-09\n第四个参数user_id\n第五个参数是clear,如true");
return;
}
String task_id = args[0];
String start_date = args[1];
String end_date = args[2];
String user_id = "0";
if (args.length >= 4) {
user_id = args[3];
}
String clear = "";
if (args.length >= 5) {
clear = args[4];
}
String url = String.format(APPLY_EMAIL_URL, task_id, start_date,
end_date, user_id, clear);
while (true) {
String response = request(url);
JSONObject json = JSONObject.fromObject(response);
String error = json.getString("error");
if (StringUtils.isNotBlank(error)) {
System.out.println("发送邮件结束:error:" + error);
break;
}
JSONArray usersJson = json.getJSONArray("users");
if (usersJson.size() == 0) {
System.out.println("发送邮件结束");
break;
}
String template = json.getString("template");
String title = json.getString("title");
int i = 1;
try {
List failed1 = new ArrayList();
for (Object _userJson : usersJson) {
send(_userJson, title, template, i, failed1,
usersJson.size());
i++;
}
if (failed1.size() == 0) {
System.out.println("发送邮件结束一批");
continue;
}
System.out.println("第一次发送失败的邮箱列表" + failed1);
Thread.sleep(1 * 60 * 60 * 1000);
List failed2 = new ArrayList();
i = 1;
for (Object userJson : failed1) {
send(userJson, title, template, i, failed2, failed1.size());
i++;
}
if (failed2.size() == 0) {
System.out.println("failed1发送邮件结束一批");
continue;
}
System.out.println("第二次发送失败的邮箱列表" + failed2);
Thread.sleep(1 * 60 * 60 * 1000);
List failed3 = new ArrayList();
i = 1;
for (Object userJson : failed2) {
send(userJson, title, template, i, failed3, failed2.size());
i++;
}
if (failed3.size() == 0) {
System.out.println("failed2发送邮件结束一批");
continue;
}
System.out.println("第三次发送失败的邮箱列表" + failed3);
Thread.sleep(1 * 60 * 60 * 1000);
List failed4 = new ArrayList();
i = 1;
for (Object userJson : failed3) {
send(userJson, title, template, i, failed4, failed3.size());
i++;
}
System.out.println("最终发送失败的邮箱列表:" + failed4);
} catch (Exception e) {
e.printStackTrace();
}
}
}

线上正式环境运行截图:

JavaMailSender 多个收件人 java批量发送邮件_json