1.修改邮件发送为异步处理
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package vvpkassistant.mail.service;
|
||||
|
||||
import cn.dev33.satoken.temp.SaTempUtil;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.extra.mail.MailUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
@@ -56,160 +57,167 @@ public class MailServiceImpl implements MailService {
|
||||
if (emailSendCache.getIfPresent(emailAddress) != null) {
|
||||
throw new BusinessException(ErrorCode.EMAIL_SEND_FREQUENT);
|
||||
}
|
||||
MailUtil.send(emailAddress, "激活你的账号", "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"en\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>Account Activation</title>\n" +
|
||||
" <style>\n" +
|
||||
" * {\n" +
|
||||
" margin: 0;\n" +
|
||||
" padding: 0;\n" +
|
||||
" box-sizing: border-box;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" body {\n" +
|
||||
" font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n" +
|
||||
" background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n" +
|
||||
" min-height: 100vh;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" padding: 20px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .container {\n" +
|
||||
" background: white;\n" +
|
||||
" border-radius: 12px;\n" +
|
||||
" box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);\n" +
|
||||
" padding: 40px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" max-width: 400px;\n" +
|
||||
" width: 100%;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .icon {\n" +
|
||||
" width: 60px;\n" +
|
||||
" height: 60px;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border-radius: 50%;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" margin: 0 auto 20px;\n" +
|
||||
" color: white;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" h1 {\n" +
|
||||
" color: #333;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" margin-bottom: 10px;\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .subtitle {\n" +
|
||||
" color: #666;\n" +
|
||||
" font-size: 16px;\n" +
|
||||
" margin-bottom: 30px;\n" +
|
||||
" line-height: 1.5;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .activate-button {\n" +
|
||||
" display: inline-block;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" padding: 15px 30px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" font-size: 18px;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
" color: white;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" transition: all 0.3s ease;\n" +
|
||||
" box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:hover {\n" +
|
||||
" background: #45a049;\n" +
|
||||
" transform: translateY(-2px);\n" +
|
||||
" box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:active {\n" +
|
||||
" transform: translateY(0);\n" +
|
||||
" box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info {\n" +
|
||||
" background: #e3f2fd;\n" +
|
||||
" border-left: 4px solid #2196F3;\n" +
|
||||
" padding: 15px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" text-align: left;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-title {\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" color: #1976D2;\n" +
|
||||
" margin-bottom: 5px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-text {\n" +
|
||||
" color: #424242;\n" +
|
||||
" font-size: 14px;\n" +
|
||||
" line-height: 1.4;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .footer {\n" +
|
||||
" margin-top: 30px;\n" +
|
||||
" padding-top: 20px;\n" +
|
||||
" border-top: 1px solid #eee;\n" +
|
||||
" color: #999;\n" +
|
||||
" font-size: 12px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" @media (max-width: 480px) {\n" +
|
||||
" .container {\n" +
|
||||
" padding: 30px 20px;\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .verification-code {\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" letter-spacing: 2px;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"container\">\n" +
|
||||
" <div class=\"icon\">✉</div>\n" +
|
||||
" \n" +
|
||||
" <h1>Account Activation</h1>\n" +
|
||||
" <p class=\"subtitle\">Please click the button below to activate your account</p>\n" +
|
||||
" \n" +
|
||||
" <a href=\""+ activateUrl+ token + "\" class=\"activate-button\">\n" +
|
||||
" Activate Account\n" +
|
||||
" </a>\n" +
|
||||
" \n" +
|
||||
" <div class=\"info\">\n" +
|
||||
" <div class=\"info-title\">Important Notice:</div>\n" +
|
||||
" <div class=\"info-text\">\n" +
|
||||
" • This activation link is valid for 24 hours<br>\n" +
|
||||
" • Please do not share this link with anyone<br>\n" +
|
||||
" • If you didn't register an account, please ignore this message\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" \n" +
|
||||
" <div class=\"footer\">\n" +
|
||||
" This is an automated message. Please do not reply to this email.\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
"</body>\n" +
|
||||
"</html>\n", true);
|
||||
ThreadUtil.execute(() -> {
|
||||
try {
|
||||
MailUtil.send(emailAddress, "激活你的账号", "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"en\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>Account Activation</title>\n" +
|
||||
" <style>\n" +
|
||||
" * {\n" +
|
||||
" margin: 0;\n" +
|
||||
" padding: 0;\n" +
|
||||
" box-sizing: border-box;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" body {\n" +
|
||||
" font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n" +
|
||||
" background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n" +
|
||||
" min-height: 100vh;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" padding: 20px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .container {\n" +
|
||||
" background: white;\n" +
|
||||
" border-radius: 12px;\n" +
|
||||
" box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);\n" +
|
||||
" padding: 40px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" max-width: 400px;\n" +
|
||||
" width: 100%;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .icon {\n" +
|
||||
" width: 60px;\n" +
|
||||
" height: 60px;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border-radius: 50%;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" margin: 0 auto 20px;\n" +
|
||||
" color: white;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" h1 {\n" +
|
||||
" color: #333;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" margin-bottom: 10px;\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .subtitle {\n" +
|
||||
" color: #666;\n" +
|
||||
" font-size: 16px;\n" +
|
||||
" margin-bottom: 30px;\n" +
|
||||
" line-height: 1.5;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .activate-button {\n" +
|
||||
" display: inline-block;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" padding: 15px 30px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" font-size: 18px;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
" color: white;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" transition: all 0.3s ease;\n" +
|
||||
" box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:hover {\n" +
|
||||
" background: #45a049;\n" +
|
||||
" transform: translateY(-2px);\n" +
|
||||
" box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:active {\n" +
|
||||
" transform: translateY(0);\n" +
|
||||
" box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info {\n" +
|
||||
" background: #e3f2fd;\n" +
|
||||
" border-left: 4px solid #2196F3;\n" +
|
||||
" padding: 15px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" text-align: left;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-title {\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" color: #1976D2;\n" +
|
||||
" margin-bottom: 5px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-text {\n" +
|
||||
" color: #424242;\n" +
|
||||
" font-size: 14px;\n" +
|
||||
" line-height: 1.4;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .footer {\n" +
|
||||
" margin-top: 30px;\n" +
|
||||
" padding-top: 20px;\n" +
|
||||
" border-top: 1px solid #eee;\n" +
|
||||
" color: #999;\n" +
|
||||
" font-size: 12px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" @media (max-width: 480px) {\n" +
|
||||
" .container {\n" +
|
||||
" padding: 30px 20px;\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .verification-code {\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" letter-spacing: 2px;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"container\">\n" +
|
||||
" <div class=\"icon\">✉</div>\n" +
|
||||
" \n" +
|
||||
" <h1>Account Activation</h1>\n" +
|
||||
" <p class=\"subtitle\">Please click the button below to activate your account</p>\n" +
|
||||
" \n" +
|
||||
" <a href=\""+ activateUrl+ token + "\" class=\"activate-button\">\n" +
|
||||
" Activate Account\n" +
|
||||
" </a>\n" +
|
||||
" \n" +
|
||||
" <div class=\"info\">\n" +
|
||||
" <div class=\"info-title\">Important Notice:</div>\n" +
|
||||
" <div class=\"info-text\">\n" +
|
||||
" • This activation link is valid for 24 hours<br>\n" +
|
||||
" • Please do not share this link with anyone<br>\n" +
|
||||
" • If you didn't register an account, please ignore this message\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" \n" +
|
||||
" <div class=\"footer\">\n" +
|
||||
" This is an automated message. Please do not reply to this email.\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
"</body>\n" +
|
||||
"</html>\n", true);
|
||||
log.info("账号激活邮件发送成功,邮箱地址:{},用户 Id:{}", emailAddress,userId);
|
||||
} catch (Exception e) {
|
||||
log.error("账号激活邮件发送失败,邮箱地址:{},用户 Id:{}",emailAddress,userId);
|
||||
}
|
||||
});
|
||||
emailSendCache.put(emailAddress, userId);
|
||||
}
|
||||
|
||||
@@ -220,160 +228,168 @@ public class MailServiceImpl implements MailService {
|
||||
if (emailSendCache.getIfPresent(emailAddress) != null) {
|
||||
throw new BusinessException(ErrorCode.EMAIL_SEND_FREQUENT);
|
||||
}
|
||||
MailUtil.send(emailAddress, "验证你的邮箱", "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"en\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>Account Activation</title>\n" +
|
||||
" <style>\n" +
|
||||
" * {\n" +
|
||||
" margin: 0;\n" +
|
||||
" padding: 0;\n" +
|
||||
" box-sizing: border-box;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" body {\n" +
|
||||
" font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n" +
|
||||
" background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n" +
|
||||
" min-height: 100vh;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" padding: 20px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .container {\n" +
|
||||
" background: white;\n" +
|
||||
" border-radius: 12px;\n" +
|
||||
" box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);\n" +
|
||||
" padding: 40px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" max-width: 400px;\n" +
|
||||
" width: 100%;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .icon {\n" +
|
||||
" width: 60px;\n" +
|
||||
" height: 60px;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border-radius: 50%;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" margin: 0 auto 20px;\n" +
|
||||
" color: white;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" h1 {\n" +
|
||||
" color: #333;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" margin-bottom: 10px;\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .subtitle {\n" +
|
||||
" color: #666;\n" +
|
||||
" font-size: 16px;\n" +
|
||||
" margin-bottom: 30px;\n" +
|
||||
" line-height: 1.5;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .activate-button {\n" +
|
||||
" display: inline-block;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" padding: 15px 30px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" font-size: 18px;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
" color: white;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" transition: all 0.3s ease;\n" +
|
||||
" box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:hover {\n" +
|
||||
" background: #45a049;\n" +
|
||||
" transform: translateY(-2px);\n" +
|
||||
" box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:active {\n" +
|
||||
" transform: translateY(0);\n" +
|
||||
" box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info {\n" +
|
||||
" background: #e3f2fd;\n" +
|
||||
" border-left: 4px solid #2196F3;\n" +
|
||||
" padding: 15px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" text-align: left;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-title {\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" color: #1976D2;\n" +
|
||||
" margin-bottom: 5px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-text {\n" +
|
||||
" color: #424242;\n" +
|
||||
" font-size: 14px;\n" +
|
||||
" line-height: 1.4;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .footer {\n" +
|
||||
" margin-top: 30px;\n" +
|
||||
" padding-top: 20px;\n" +
|
||||
" border-top: 1px solid #eee;\n" +
|
||||
" color: #999;\n" +
|
||||
" font-size: 12px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" @media (max-width: 480px) {\n" +
|
||||
" .container {\n" +
|
||||
" padding: 30px 20px;\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .verification-code {\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" letter-spacing: 2px;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"container\">\n" +
|
||||
" <div class=\"icon\">✉</div>\n" +
|
||||
" \n" +
|
||||
" <h1>Verification Mail</h1>\n" +
|
||||
" <p class=\"subtitle\">Please click the button below to verification your mail</p>\n" +
|
||||
" \n" +
|
||||
" <a href=\""+ verificationMailUrl+ token + "\" class=\"activate-button\">\n" +
|
||||
" Verification\n" +
|
||||
" </a>\n" +
|
||||
" \n" +
|
||||
" <div class=\"info\">\n" +
|
||||
" <div class=\"info-title\">Important Notice:</div>\n" +
|
||||
" <div class=\"info-text\">\n" +
|
||||
" • This activation link is valid for 10 minutes<br>\n" +
|
||||
" • Please do not share this link with anyone<br>\n" +
|
||||
" • If you didn't register an account, please ignore this message\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" \n" +
|
||||
" <div class=\"footer\">\n" +
|
||||
" This is an automated message. Please do not reply to this email.\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
"</body>\n" +
|
||||
"</html>\n", true);
|
||||
ThreadUtil.execAsync(() ->{
|
||||
try {
|
||||
MailUtil.send(emailAddress, "验证你的邮箱", "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"en\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>Account Activation</title>\n" +
|
||||
" <style>\n" +
|
||||
" * {\n" +
|
||||
" margin: 0;\n" +
|
||||
" padding: 0;\n" +
|
||||
" box-sizing: border-box;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" body {\n" +
|
||||
" font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n" +
|
||||
" background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n" +
|
||||
" min-height: 100vh;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" padding: 20px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .container {\n" +
|
||||
" background: white;\n" +
|
||||
" border-radius: 12px;\n" +
|
||||
" box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);\n" +
|
||||
" padding: 40px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" max-width: 400px;\n" +
|
||||
" width: 100%;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .icon {\n" +
|
||||
" width: 60px;\n" +
|
||||
" height: 60px;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border-radius: 50%;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" margin: 0 auto 20px;\n" +
|
||||
" color: white;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" h1 {\n" +
|
||||
" color: #333;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" margin-bottom: 10px;\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .subtitle {\n" +
|
||||
" color: #666;\n" +
|
||||
" font-size: 16px;\n" +
|
||||
" margin-bottom: 30px;\n" +
|
||||
" line-height: 1.5;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .activate-button {\n" +
|
||||
" display: inline-block;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" padding: 15px 30px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" font-size: 18px;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
" color: white;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" transition: all 0.3s ease;\n" +
|
||||
" box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:hover {\n" +
|
||||
" background: #45a049;\n" +
|
||||
" transform: translateY(-2px);\n" +
|
||||
" box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:active {\n" +
|
||||
" transform: translateY(0);\n" +
|
||||
" box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info {\n" +
|
||||
" background: #e3f2fd;\n" +
|
||||
" border-left: 4px solid #2196F3;\n" +
|
||||
" padding: 15px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" text-align: left;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-title {\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" color: #1976D2;\n" +
|
||||
" margin-bottom: 5px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-text {\n" +
|
||||
" color: #424242;\n" +
|
||||
" font-size: 14px;\n" +
|
||||
" line-height: 1.4;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .footer {\n" +
|
||||
" margin-top: 30px;\n" +
|
||||
" padding-top: 20px;\n" +
|
||||
" border-top: 1px solid #eee;\n" +
|
||||
" color: #999;\n" +
|
||||
" font-size: 12px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" @media (max-width: 480px) {\n" +
|
||||
" .container {\n" +
|
||||
" padding: 30px 20px;\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .verification-code {\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" letter-spacing: 2px;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"container\">\n" +
|
||||
" <div class=\"icon\">✉</div>\n" +
|
||||
" \n" +
|
||||
" <h1>Verification Mail</h1>\n" +
|
||||
" <p class=\"subtitle\">Please click the button below to verification your mail</p>\n" +
|
||||
" \n" +
|
||||
" <a href=\""+ verificationMailUrl+ token + "\" class=\"activate-button\">\n" +
|
||||
" Verification\n" +
|
||||
" </a>\n" +
|
||||
" \n" +
|
||||
" <div class=\"info\">\n" +
|
||||
" <div class=\"info-title\">Important Notice:</div>\n" +
|
||||
" <div class=\"info-text\">\n" +
|
||||
" • This activation link is valid for 10 minutes<br>\n" +
|
||||
" • Please do not share this link with anyone<br>\n" +
|
||||
" • If you didn't register an account, please ignore this message\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" \n" +
|
||||
" <div class=\"footer\">\n" +
|
||||
" This is an automated message. Please do not reply to this email.\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
"</body>\n" +
|
||||
"</html>\n", true);
|
||||
log.info("邮箱验证发送失败,邮箱地址:{},用户 Id: {}",emailAddress,userId );
|
||||
}catch (Exception e) {
|
||||
log.error("邮箱验证发送失败,邮箱地址:{},用户 Id: {}",emailAddress,userId );
|
||||
}
|
||||
});
|
||||
|
||||
emailSendCache.put(emailAddress, userId);
|
||||
}
|
||||
|
||||
@@ -410,160 +426,167 @@ public class MailServiceImpl implements MailService {
|
||||
public void sendForgetPassWordMail(String mailAddress, Integer userId) {
|
||||
if (checkCache(mailAddress)){
|
||||
String token = SaTempUtil.createToken(userId, 600);
|
||||
MailUtil.send(mailAddress, "验证你的邮箱", "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"en\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>Account Activation</title>\n" +
|
||||
" <style>\n" +
|
||||
" * {\n" +
|
||||
" margin: 0;\n" +
|
||||
" padding: 0;\n" +
|
||||
" box-sizing: border-box;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" body {\n" +
|
||||
" font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n" +
|
||||
" background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n" +
|
||||
" min-height: 100vh;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" padding: 20px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .container {\n" +
|
||||
" background: white;\n" +
|
||||
" border-radius: 12px;\n" +
|
||||
" box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);\n" +
|
||||
" padding: 40px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" max-width: 400px;\n" +
|
||||
" width: 100%;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .icon {\n" +
|
||||
" width: 60px;\n" +
|
||||
" height: 60px;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border-radius: 50%;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" margin: 0 auto 20px;\n" +
|
||||
" color: white;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" h1 {\n" +
|
||||
" color: #333;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" margin-bottom: 10px;\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .subtitle {\n" +
|
||||
" color: #666;\n" +
|
||||
" font-size: 16px;\n" +
|
||||
" margin-bottom: 30px;\n" +
|
||||
" line-height: 1.5;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .activate-button {\n" +
|
||||
" display: inline-block;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" padding: 15px 30px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" font-size: 18px;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
" color: white;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" transition: all 0.3s ease;\n" +
|
||||
" box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:hover {\n" +
|
||||
" background: #45a049;\n" +
|
||||
" transform: translateY(-2px);\n" +
|
||||
" box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:active {\n" +
|
||||
" transform: translateY(0);\n" +
|
||||
" box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info {\n" +
|
||||
" background: #e3f2fd;\n" +
|
||||
" border-left: 4px solid #2196F3;\n" +
|
||||
" padding: 15px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" text-align: left;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-title {\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" color: #1976D2;\n" +
|
||||
" margin-bottom: 5px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-text {\n" +
|
||||
" color: #424242;\n" +
|
||||
" font-size: 14px;\n" +
|
||||
" line-height: 1.4;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .footer {\n" +
|
||||
" margin-top: 30px;\n" +
|
||||
" padding-top: 20px;\n" +
|
||||
" border-top: 1px solid #eee;\n" +
|
||||
" color: #999;\n" +
|
||||
" font-size: 12px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" @media (max-width: 480px) {\n" +
|
||||
" .container {\n" +
|
||||
" padding: 30px 20px;\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .verification-code {\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" letter-spacing: 2px;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"container\">\n" +
|
||||
" <div class=\"icon\">✉</div>\n" +
|
||||
" \n" +
|
||||
" <h1>Verification Mail</h1>\n" +
|
||||
" <p class=\"subtitle\">Please click the button below to reset your password</p>\n" +
|
||||
" \n" +
|
||||
" <a href=\""+ forgetPassWordUrl + token + "\" class=\"activate-button\">\n" +
|
||||
" Reset PassWord\n" +
|
||||
" </a>\n" +
|
||||
" \n" +
|
||||
" <div class=\"info\">\n" +
|
||||
" <div class=\"info-title\">Important Notice:</div>\n" +
|
||||
" <div class=\"info-text\">\n" +
|
||||
" • This activation link is valid for 10 minutes<br>\n" +
|
||||
" • Please do not share this link with anyone<br>\n" +
|
||||
" • If you didn't register an account, please ignore this message\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" \n" +
|
||||
" <div class=\"footer\">\n" +
|
||||
" This is an automated message. Please do not reply to this email.\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
"</body>\n" +
|
||||
"</html>\n", true);
|
||||
ThreadUtil.execAsync(() ->{
|
||||
try {
|
||||
MailUtil.send(mailAddress, "验证你的邮箱", "<!DOCTYPE html>\n" +
|
||||
"<html lang=\"en\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
|
||||
" <title>Account Activation</title>\n" +
|
||||
" <style>\n" +
|
||||
" * {\n" +
|
||||
" margin: 0;\n" +
|
||||
" padding: 0;\n" +
|
||||
" box-sizing: border-box;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" body {\n" +
|
||||
" font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n" +
|
||||
" background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n" +
|
||||
" min-height: 100vh;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" padding: 20px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .container {\n" +
|
||||
" background: white;\n" +
|
||||
" border-radius: 12px;\n" +
|
||||
" box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);\n" +
|
||||
" padding: 40px;\n" +
|
||||
" text-align: center;\n" +
|
||||
" max-width: 400px;\n" +
|
||||
" width: 100%;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .icon {\n" +
|
||||
" width: 60px;\n" +
|
||||
" height: 60px;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border-radius: 50%;\n" +
|
||||
" display: flex;\n" +
|
||||
" align-items: center;\n" +
|
||||
" justify-content: center;\n" +
|
||||
" margin: 0 auto 20px;\n" +
|
||||
" color: white;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" h1 {\n" +
|
||||
" color: #333;\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" margin-bottom: 10px;\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .subtitle {\n" +
|
||||
" color: #666;\n" +
|
||||
" font-size: 16px;\n" +
|
||||
" margin-bottom: 30px;\n" +
|
||||
" line-height: 1.5;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .activate-button {\n" +
|
||||
" display: inline-block;\n" +
|
||||
" background: #4CAF50;\n" +
|
||||
" border: none;\n" +
|
||||
" border-radius: 8px;\n" +
|
||||
" padding: 15px 30px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" font-size: 18px;\n" +
|
||||
" font-weight: bold;\n" +
|
||||
" color: white;\n" +
|
||||
" text-decoration: none;\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" transition: all 0.3s ease;\n" +
|
||||
" box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:hover {\n" +
|
||||
" background: #45a049;\n" +
|
||||
" transform: translateY(-2px);\n" +
|
||||
" box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .activate-button:active {\n" +
|
||||
" transform: translateY(0);\n" +
|
||||
" box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info {\n" +
|
||||
" background: #e3f2fd;\n" +
|
||||
" border-left: 4px solid #2196F3;\n" +
|
||||
" padding: 15px;\n" +
|
||||
" margin: 20px 0;\n" +
|
||||
" text-align: left;\n" +
|
||||
" border-radius: 4px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-title {\n" +
|
||||
" font-weight: 600;\n" +
|
||||
" color: #1976D2;\n" +
|
||||
" margin-bottom: 5px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .info-text {\n" +
|
||||
" color: #424242;\n" +
|
||||
" font-size: 14px;\n" +
|
||||
" line-height: 1.4;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .footer {\n" +
|
||||
" margin-top: 30px;\n" +
|
||||
" padding-top: 20px;\n" +
|
||||
" border-top: 1px solid #eee;\n" +
|
||||
" color: #999;\n" +
|
||||
" font-size: 12px;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" @media (max-width: 480px) {\n" +
|
||||
" .container {\n" +
|
||||
" padding: 30px 20px;\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" .verification-code {\n" +
|
||||
" font-size: 24px;\n" +
|
||||
" letter-spacing: 2px;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"</head>\n" +
|
||||
"<body>\n" +
|
||||
" <div class=\"container\">\n" +
|
||||
" <div class=\"icon\">✉</div>\n" +
|
||||
" \n" +
|
||||
" <h1>Verification Mail</h1>\n" +
|
||||
" <p class=\"subtitle\">Please click the button below to reset your password</p>\n" +
|
||||
" \n" +
|
||||
" <a href=\""+ forgetPassWordUrl + token + "\" class=\"activate-button\">\n" +
|
||||
" Reset PassWord\n" +
|
||||
" </a>\n" +
|
||||
" \n" +
|
||||
" <div class=\"info\">\n" +
|
||||
" <div class=\"info-title\">Important Notice:</div>\n" +
|
||||
" <div class=\"info-text\">\n" +
|
||||
" • This activation link is valid for 10 minutes<br>\n" +
|
||||
" • Please do not share this link with anyone<br>\n" +
|
||||
" • If you didn't register an account, please ignore this message\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" \n" +
|
||||
" <div class=\"footer\">\n" +
|
||||
" This is an automated message. Please do not reply to this email.\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
"</body>\n" +
|
||||
"</html>\n", true);
|
||||
log.info("找回密码邮件发送成功,邮箱地址:{},用户 Id:{}", mailAddress,userId);
|
||||
}catch (Exception e) {
|
||||
log.error("找回密码邮件发送失败,邮箱地址:{},用户 Id:{}", mailAddress,userId);
|
||||
}
|
||||
});
|
||||
emailSendCache.put(mailAddress, userId);
|
||||
}
|
||||
|
||||
@@ -583,9 +606,15 @@ public class MailServiceImpl implements MailService {
|
||||
String code = RandomUtil.randomString(6);
|
||||
emailSendCache.put(mailModel.getMailAddress(), code);
|
||||
CacheHolder.VERIFICATION_MAIL.put(code, mailModel.getMailAddress());
|
||||
MailUtil.send(mailModel.getMailAddress(),"your Verification code is :" + code,
|
||||
"your Verification code is :" + code,false);
|
||||
log.info("sendMailto:{},Verification code is :{}", mailModel.getMailAddress(),code);
|
||||
ThreadUtil.execAsync(() -> {
|
||||
try {
|
||||
MailUtil.send(mailModel.getMailAddress(),"your Verification code is :" + code,
|
||||
"your Verification code is :" + code,false);
|
||||
log.info("sendMailto:{},Verification code is :{}", mailModel.getMailAddress(),code);
|
||||
}catch (Exception e){
|
||||
log.error("发送邮件失败, address={}, code={}", mailModel.getMailAddress(), code, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user