本编以qq邮箱为例,开启POP2/SMTP服务,按照操作,发送短信到指定号码后,页面就返回一串随机密码。将这里的密码保存好。接下来会使用它。
<dependencies>
<!-- email -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-cron</artifactId>
<version>4.6.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>dnsjava</groupId>
<artifactId>dnsjava</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
文件文件中的邮箱信息格式如下:
251236160
254923348
269380365
270061097
270371508
代码如下:
public static List<String> readFileByLines(String filePath) {
List<String> qqMailList = new ArrayList<>();
File file = new File(filePath);
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
String tempString = null;
int line = 1;
// 一次读入一行,直到读入null为文件结束
while ((tempString = reader.readLine()) != null) {
qqMailList.add(tempString + "@qq.com");
line++;
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
}
}
}
return qqMailList;
}
验证邮箱是否有效,是通过DNS的MX记录来验证的。
DNS中除了A记录(域名-IP映射)之外,还有MX记录(邮件交换记录),CNAME记录(别名)。MX记录就是为了在发送邮件时使用友好域名规则,比如我们发送到QQ邮箱xxx@qq.com。我们填写地址是到“qq.com”,但实际上可能服务器地址千奇百怪。在设置DNS时可以顺带设置MX记录。
代码如下:
public static boolean valid(String toMail, String domain) {
if(StringUtils.isBlank(toMail) || StringUtils.isBlank(domain)) return false;
if(!StringUtils.contains(toMail, '@')) return false;
String host = toMail.substring(toMail.indexOf('@') + 1);
if(host.equals(domain)) return false;
Socket socket = new Socket();
try {
// 查找mx记录
Record[] mxRecords = new Lookup(host, Type.MX).run();
if(ArrayUtils.isEmpty(mxRecords)) return false;
// 邮件服务器地址
String mxHost = ((MXRecord)mxRecords[0]).getTarget().toString();
if(mxRecords.length > 1) { // 优先级排序
List<Record> arrRecords = new ArrayList<Record>();
Collections.addAll(arrRecords, mxRecords);
Collections.sort(arrRecords, new Comparator<Record>() {
public int compare(Record o1, Record o2) {
return new CompareToBuilder().append(((MXRecord)o1).getPriority(), ((MXRecord)o2).getPriority()).toComparison();
}
});
mxHost = ((MXRecord)arrRecords.get(0)).getTarget().toString();
}
// 开始smtp
socket.connect(new InetSocketAddress(mxHost, 25));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(socket.getInputStream())));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
// 超时时间(毫秒)
long timeout = 6000;
// 睡眠时间片段(50毫秒)
int sleepSect = 50;
// 连接(服务器是否就绪)
if(getResponseCode(timeout, sleepSect, bufferedReader) != 220) {
return false;
}
// 握手
bufferedWriter.write("HELO " + domain + "\r\n");
bufferedWriter.flush();
if(getResponseCode(timeout, sleepSect, bufferedReader) != 250) {
return false;
}
// 身份
bufferedWriter.write("MAIL FROM: <check@" + domain + ">\r\n");
bufferedWriter.flush();
if(getResponseCode(timeout, sleepSect, bufferedReader) != 250) {
return false;
}
// 验证
bufferedWriter.write("RCPT TO: <" + toMail + ">\r\n");
bufferedWriter.flush();
if(getResponseCode(timeout, sleepSect, bufferedReader) != 250) {
return false;
}
// 断开
bufferedWriter.write("QUIT\r\n");
bufferedWriter.flush();
return true;
} catch (NumberFormatException e) {
} catch (TextParseException e) {
} catch (IOException e) {
} catch (InterruptedException e) {
} finally {
try {
socket.close();
} catch (IOException e) {
}
}
return false;
}
需要配置发送邮件的基本信息,包括邮箱服务的IP地址,端口号,自己的邮箱地址,邮箱授权密码(第一步在邮箱后台获取的密码)。
邮件内容包括:收件人信息,抄送人信息,邮件标题,邮件内容,邮件附件等信息
示例代码如下:
public boolean sendSSLEmailWithCC(List<String> listEmails, String title, String content ,List<File> attachments) throws NoSuchProviderException, SendFailedException, ParseException,
MessagingException, NullPointerException, UnsupportedEncodingException {
LOGGER.info("开始发送邮件,email==>"+listEmails+",title==>"+title);
Properties props = System.getProperties();
MailBean mailBean = new MailBean();
props.put("mail.smtp.host", mailBean.getHost());
// 指定协议
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.port", mailBean.getSSLport());
props.put("mail.smtp.starttls.enable", mailBean.getStarttlsEnable());
props.put("mail.smtp.auth", mailBean.getAuth());
props.put("mail.smtp.connectiontimeout", mailBean.getConnectiontimeout());
props.put("mail.smtp.timeout", mailBean.getTimeout());
props.put("mail.smtp.debug", true);
Transport transport = null;
Session session = Session.getDefaultInstance(props, null);
transport = session.getTransport("smtp");
transport.connect(mailBean.getHost(), mailBean.getAccount(), mailBean.getPassword());
// 组装收件人邮箱
MimeMessage msg = new MimeMessage(session);
msg.setSentDate(new Date());
InternetAddress fromAddress = new InternetAddress(mailBean.getAccount(), nickname);
msg.setFrom(fromAddress);
InternetAddress[] toAddress = new InternetAddress[listEmails.size()];
for(int k = 0;k<listEmails.size();k++){
String emailAddress = listEmails.get(k);
new InternetAddress(emailAddress);
toAddress[k]=new InternetAddress(emailAddress);
}
// 向multipart对象中添加邮件的各个部分内容,包括文本内容和附件
Multipart multipart = new MimeMultipart();
BodyPart contentPart = new MimeBodyPart();
contentPart.setContent(content, "text/html; charset=utf-8");
multipart.addBodyPart(contentPart);
// 将multipart对象放到message中
msg.setContent(multipart);
LOGGER.debug("当前需要发送邮件的地址信息============>{}"+Arrays.deepToString(toAddress));
msg.addRecipients(Message.RecipientType.TO, toAddress);
msg.setSubject(title, "UTF-8");
//发送文本邮件
transport.sendMessage(msg, msg.getAllRecipients());
LOGGER.info("邮件已发送");
return true;
}
本地测试我就使用的main方法简单运行了。
示例代码如下:
/**
* 移除无法抵达的邮箱
*/
public static List<String> removeUnreachableEmail(List<String> listEmails){
List<String> filtedList = new ArrayList<>();
if(CollectionUtil.isNotEmpty(listEmails)){
filtedList = listEmails.stream().filter(e -> MailValid.valid(e, "jootmir.org"))
.collect(Collectors.toList());
}
return filtedList;
}
private String nickname ="不安分的猿人";//发送者,显示的发件人名字
protected static Log LOGGER = LogFactory.getLog(MailUtil.class);
public static void main(String[] args) throws IOException, MessagingException, NoSuchProviderException,SendFailedException, ParseException {
MailUtil mailUtil = new MailUtil();
List<String> listEmails = removeUnreachableEmail(FileUtils.readFileByLines("E:\\下载\\2019-09-02_22-12-07.txt"));
String emailTile = "珍藏多年的编程资源分享给你!";
StringBuffer emailContent = new StringBuffer();
FileUtils.readToBuffer(emailContent,"E:\\下载\\cb8oj-qgbhj.html");
List<File> attrachList = new ArrayList<>();
attrachList.add(new File("E:\\下载\\公众号二维码.jpg"));
mailUtil.sendSSLEmailWithCC(listEmails, emailTile, emailContent.toString(), attrachList);
}
Java发邮件有很多种方式:
1.使用JavaMail发送邮件
2.Spring Boot中使用JavaMailSender发送邮件
3.开源框架Simple Java Mail
1.发送无效邮箱的时候,会直接抛出异常。javax.mail.SendFailedException: Invalid Address 与 SMTPAddressFailedException 抛错。
解决方式:在发送邮件前,先校验所有的邮箱是否有效。代码已实现。
1. Java 发送邮件的几种方式
https://blog.csdn.net/qq_32371887/article/details/72821291
2. 使用 javamail 实现发送邮件(QQ邮箱和163邮箱)
https://blog.csdn.net/zouxucong/article/details/60756482
3. Java 与邮件系统交互之使用 Socket 验证邮箱是否存在
https://www.cnblogs.com/Johness/p/javaemail_usesockettocheckemailaddressvalid.html