Files
Sdf1_login/txt/EmailManager.txt
T

211 lines
8.6 KiB
Plaintext

package Sdf1_login;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Base64;
import java.util.logging.Logger;
public class EmailManager {
private final ConfigManager config;
private final Logger logger;
/**
* 发送SMTP验证码
*/
public boolean sendVerifyCode(String to, String code) {
if (!isConfigured()) {
plugin.getLogger().severe(
"[Sdf1_login] SMTP未配置完整,"
+ "请检查SMTP设置.txt");
return false;
}
String subject =
"[Sdf1_login] SMTP配置验证码";
String body = "您的SMTP配置验证码是: "
+ code + "\n"
+ "验证码5分钟内有效。\n"
+ "如非本人操作请忽略此邮件。";
try {
return sendEmail(to, subject, body);
} catch (Exception e) {
plugin.getLogger().severe(
"[Sdf1_login] 邮件发送异常: "
+ e.getClass().getSimpleName()
+ ": " + e.getMessage());
if (e.getCause() != null) {
plugin.getLogger().severe(
"[Sdf1_login] 根因: "
+ e.getCause().getMessage());
}
return false;
}
}
public EmailManager(ConfigManager config) {
this.config = config;
this.logger = Logger.getLogger("Sdf1_login");
}
/**
* 检查SMTP是否已配置
*/
public boolean isConfigured() {
String host = config.getSmtp("smtp地址");
String user = config.getSmtp("发件邮箱");
String pass = config.getSmtp("授权码");
return host != null && !host.isEmpty()
&& user != null && !user.isEmpty()
&& pass != null && !pass.isEmpty();
}
/**
* 发送验证码,返回是否成功发起
*/
public boolean sendVerifyCode(String to, String player, String code) {
if (!isConfigured()) {
logger.warning("[Sdf1_login] SMTP未配置,无法发送验证码到 " + to);
return false;
}
logger.info("[Sdf1_login] 发送验证码到 " + to + " (玩家: " + player + ")");
return sendEmailSync(to, "Sdf1_login 验证码",
"玩家 " + player + " 的验证码: " + code);
}
/**
* 发送临时密码,返回是否成功发起
*/
public boolean sendTempPassword(String to, String player, String tempPwd) {
if (!isConfigured()) {
logger.warning("[Sdf1_login] SMTP未配置,无法发送临时密码到 " + to);
return false;
}
logger.info("[Sdf1_login] 发送临时密码到 " + to + " (玩家: " + player + ")");
return sendEmailSync(to, "Sdf1_login 临时密码",
"玩家 " + player + " 的临时密码: " + tempPwd + "\n请尽快登录并修改密码!");
}
private boolean sendEmailSync(String to, String subject, String body) {
final boolean[] result = {false};
Thread t = new Thread(() -> {
try {
result[0] = sendEmail(to, subject, body);
} catch (Exception e) {
logger.severe("[Sdf1_login] 邮件线程异常: " + e.getMessage());
}
}, "Sdf1_login-SMTP");
t.setDaemon(true);
t.start();
try { t.join(15000); } catch (InterruptedException ignored) {}
if (t.isAlive()) {
t.interrupt();
logger.severe("[Sdf1_login] SMTP超时(15秒)");
return false;
}
return result[0];
}
private boolean sendEmail(String to, String subject, String body) {
String host = config.getSmtp("smtp地址");
String portStr = config.getSmtp("smtp端口");
String user = config.getSmtp("发件邮箱");
String pass = config.getSmtp("授权码");
String fromName = config.getSmtp("发件人名");
int port;
try { port = Integer.parseInt(portStr); } catch (Exception e) { port = 465; }
try {
String encSubject = "=?UTF-8?B?" + Base64.getEncoder().encodeToString(subject.getBytes("UTF-8")) + "?=";
String encBody = Base64.getEncoder().encodeToString(body.getBytes("UTF-8"));
if (port == 465) {
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
socket.setSoTimeout(10000);
doSmtp(socket, host, user, pass, to, encSubject, encBody, fromName);
socket.close();
} else {
Socket plainSocket = new Socket(host, port);
plainSocket.setSoTimeout(10000);
BufferedReader preReader = new BufferedReader(new InputStreamReader(plainSocket.getInputStream(), "UTF-8"));
PrintWriter preWriter = new PrintWriter(plainSocket.getOutputStream(), true);
checkResponse(preReader, "220");
sendLine(preWriter, "EHLO " + host);
checkResponse(preReader, "250");
sendLine(preWriter, "STARTTLS");
checkResponse(preReader, "220");
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslSocket = (SSLSocket) factory.createSocket(plainSocket, host, port, true);
sslSocket.startHandshake();
doSmtp(sslSocket, host, user, pass, to, encSubject, encBody, fromName);
sslSocket.close();
}
logger.info("[Sdf1_login] 邮件发送成功 -> " + to);
return true;
} catch (Exception e) {
logger.severe("[Sdf1_login] 邮件异常: " + e.getMessage());
return false;
}
}
private void doSmtp(SSLSocket socket, String host, String user, String pass,
String to, String subject, String body, String fromName) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
OutputStream rawOut = socket.getOutputStream();
PrintWriter writer = new PrintWriter(new java.io.BufferedOutputStream(rawOut), true);
checkResponse(reader, "220");
sendLine(writer, "EHLO " + host);
checkResponse(reader, "250");
sendLine(writer, "AUTH LOGIN");
checkResponse(reader, "334");
sendLine(writer, Base64.getEncoder().encodeToString(user.getBytes("UTF-8")));
checkResponse(reader, "334");
sendLine(writer, Base64.getEncoder().encodeToString(pass.getBytes("UTF-8")));
checkResponse(reader, "235");
sendLine(writer, "MAIL FROM:<" + user + ">");
checkResponse(reader, "250");
sendLine(writer, "RCPT TO:<" + to + ">");
checkResponse(reader, "250");
sendLine(writer, "DATA");
checkResponse(reader, "354");
sendLine(writer, "From: " + fromName + " <" + user + ">");
sendLine(writer, "To: <" + to + ">");
sendLine(writer, "Reply-To: <" + user + ">");
sendLine(writer, "Subject: " + subject);
sendLine(writer, "MIME-Version: 1.0");
sendLine(writer, "Content-Type: text/plain; charset=UTF-8");
sendLine(writer, "Content-Transfer-Encoding: base64");
sendLine(writer, "");
sendLine(writer, body);
sendLine(writer, ".");
checkResponse(reader, "250");
sendLine(writer, "QUIT");
}
private void sendLine(PrintWriter writer, String line) {
writer.print(line + "\r\n");
writer.flush();
}
private void checkResponse(BufferedReader reader, String expected) throws Exception {
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
if (line.length() >= 4 && Character.isDigit(line.charAt(0)) && line.charAt(3) == ' ') break;
}
String resp = sb.toString().trim();
if (!resp.startsWith(expected)) {
if (resp.startsWith("535")) logger.severe("[Sdf1_login] SMTP 535 认证失败");
throw new Exception("SMTP响应异常: 期望 " + expected + ",实际: " + resp);
}
}
}