mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-02-21 06:20:59 +08:00
fix: 解决邮件发送错误,但是前端显示已发送的问题
This commit is contained in:
@@ -6,10 +6,12 @@ import com.openisle.model.User;
|
||||
import com.openisle.repository.NotificationRepository;
|
||||
import com.openisle.repository.UserRepository;
|
||||
import com.openisle.service.EmailSender;
|
||||
import com.openisle.exception.EmailSendException;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -17,6 +19,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
@RestController
|
||||
@RequestMapping("/api/admin/users")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class AdminUserController {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
@@ -35,11 +38,15 @@ public class AdminUserController {
|
||||
user.setApproved(true);
|
||||
userRepository.save(user);
|
||||
markRegisterRequestNotificationsRead(user);
|
||||
emailSender.sendEmail(
|
||||
user.getEmail(),
|
||||
"您的注册已审核通过",
|
||||
"🎉您的注册已经审核通过, 点击以访问网站: " + websiteUrl
|
||||
);
|
||||
try {
|
||||
emailSender.sendEmail(
|
||||
user.getEmail(),
|
||||
"您的注册已审核通过",
|
||||
"🎉您的注册已经审核通过, 点击以访问网站: " + websiteUrl
|
||||
);
|
||||
} catch (EmailSendException e) {
|
||||
log.warn("Failed to send approve email to {}: {}", user.getEmail(), e.getMessage());
|
||||
}
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@@ -52,11 +59,15 @@ public class AdminUserController {
|
||||
user.setApproved(false);
|
||||
userRepository.save(user);
|
||||
markRegisterRequestNotificationsRead(user);
|
||||
emailSender.sendEmail(
|
||||
user.getEmail(),
|
||||
"您的注册已被管理员拒绝",
|
||||
"您的注册被管理员拒绝, 点击链接可以重新填写理由申请: " + websiteUrl
|
||||
);
|
||||
try {
|
||||
emailSender.sendEmail(
|
||||
user.getEmail(),
|
||||
"您的注册已被管理员拒绝",
|
||||
"您的注册被管理员拒绝, 点击链接可以重新填写理由申请: " + websiteUrl
|
||||
);
|
||||
} catch (EmailSendException e) {
|
||||
log.warn("Failed to send reject email to {}: {}", user.getEmail(), e.getMessage());
|
||||
}
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.openisle.controller;
|
||||
|
||||
import com.openisle.config.CachingConfig;
|
||||
import com.openisle.dto.*;
|
||||
import com.openisle.exception.EmailSendException;
|
||||
import com.openisle.exception.FieldException;
|
||||
import com.openisle.model.RegisterMode;
|
||||
import com.openisle.model.User;
|
||||
@@ -19,6 +20,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -83,6 +85,17 @@ public class AuthController {
|
||||
"INVITE_APPROVED"
|
||||
)
|
||||
);
|
||||
} catch (EmailSendException e) {
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(
|
||||
Map.of(
|
||||
"error",
|
||||
"邮件发送失败: " + e.getMessage(),
|
||||
"reason_code",
|
||||
"EMAIL_SEND_FAILED"
|
||||
)
|
||||
);
|
||||
} catch (FieldException e) {
|
||||
return ResponseEntity.badRequest().body(
|
||||
Map.of("field", e.getField(), "error", e.getMessage())
|
||||
@@ -97,7 +110,20 @@ public class AuthController {
|
||||
registerModeService.getRegisterMode()
|
||||
);
|
||||
// 发送确认邮件
|
||||
userService.sendVerifyMail(user, VerifyType.REGISTER);
|
||||
try {
|
||||
userService.sendVerifyMail(user, VerifyType.REGISTER);
|
||||
} catch (EmailSendException e) {
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(
|
||||
Map.of(
|
||||
"error",
|
||||
"邮件发送失败: " + e.getMessage(),
|
||||
"reason_code",
|
||||
"EMAIL_SEND_FAILED"
|
||||
)
|
||||
);
|
||||
}
|
||||
if (!user.isApproved()) {
|
||||
notificationService.createRegisterRequestNotifications(user, user.getRegisterReason());
|
||||
}
|
||||
@@ -169,14 +195,28 @@ public class AuthController {
|
||||
}
|
||||
User user = userOpt.get();
|
||||
if (!user.isVerified()) {
|
||||
user = userService.register(
|
||||
user.getUsername(),
|
||||
user.getEmail(),
|
||||
user.getPassword(),
|
||||
user.getRegisterReason(),
|
||||
registerModeService.getRegisterMode()
|
||||
);
|
||||
userService.sendVerifyMail(user, VerifyType.REGISTER);
|
||||
user =
|
||||
userService.register(
|
||||
user.getUsername(),
|
||||
user.getEmail(),
|
||||
user.getPassword(),
|
||||
user.getRegisterReason(),
|
||||
registerModeService.getRegisterMode()
|
||||
);
|
||||
try {
|
||||
userService.sendVerifyMail(user, VerifyType.REGISTER);
|
||||
} catch (EmailSendException e) {
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(
|
||||
Map.of(
|
||||
"error",
|
||||
"Failed to send verification email: " + e.getMessage(),
|
||||
"reason_code",
|
||||
"EMAIL_SEND_FAILED"
|
||||
)
|
||||
);
|
||||
}
|
||||
return ResponseEntity.badRequest().body(
|
||||
Map.of(
|
||||
"error",
|
||||
@@ -663,7 +703,20 @@ public class AuthController {
|
||||
if (userOpt.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("error", "User not found"));
|
||||
}
|
||||
userService.sendVerifyMail(userOpt.get(), VerifyType.RESET_PASSWORD);
|
||||
try {
|
||||
userService.sendVerifyMail(userOpt.get(), VerifyType.RESET_PASSWORD);
|
||||
} catch (EmailSendException e) {
|
||||
return ResponseEntity
|
||||
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(
|
||||
Map.of(
|
||||
"error",
|
||||
"邮件发送失败: " + e.getMessage(),
|
||||
"reason_code",
|
||||
"EMAIL_SEND_FAILED"
|
||||
)
|
||||
);
|
||||
}
|
||||
return ResponseEntity.ok(Map.of("message", "Verification code sent"));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.openisle.exception;
|
||||
|
||||
/**
|
||||
* Thrown when email sending fails so callers can surface a clear error upstream.
|
||||
*/
|
||||
public class EmailSendException extends RuntimeException {
|
||||
|
||||
public EmailSendException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public EmailSendException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import com.openisle.repository.NotificationRepository;
|
||||
import com.openisle.repository.ReactionRepository;
|
||||
import com.openisle.repository.UserRepository;
|
||||
import com.openisle.service.EmailSender;
|
||||
import com.openisle.exception.EmailSendException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
@@ -17,6 +18,7 @@ import java.util.concurrent.Executor;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -26,6 +28,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
/** Service for creating and retrieving notifications. */
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class NotificationService {
|
||||
|
||||
private final NotificationRepository notificationRepository;
|
||||
@@ -108,7 +111,11 @@ public class NotificationService {
|
||||
post.getId(),
|
||||
comment.getId()
|
||||
);
|
||||
emailSender.sendEmail(user.getEmail(), "有人回复了你", url);
|
||||
try {
|
||||
emailSender.sendEmail(user.getEmail(), "有人回复了你", url);
|
||||
} catch (EmailSendException e) {
|
||||
log.warn("Failed to send notification email to {}: {}", user.getEmail(), e.getMessage());
|
||||
}
|
||||
sendCustomPush(user, "有人回复了你", url);
|
||||
} else if (type == NotificationType.REACTION && comment != null) {
|
||||
// long count = reactionRepository.countReceived(comment.getAuthor().getUsername());
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.openisle.repository.TagRepository;
|
||||
import com.openisle.repository.UserRepository;
|
||||
import com.openisle.search.SearchIndexEventPublisher;
|
||||
import com.openisle.service.EmailSender;
|
||||
import com.openisle.exception.EmailSendException;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
@@ -663,11 +664,15 @@ public class PostService {
|
||||
w.getEmail() != null &&
|
||||
!w.getDisabledEmailNotificationTypes().contains(NotificationType.LOTTERY_WIN)
|
||||
) {
|
||||
emailSender.sendEmail(
|
||||
w.getEmail(),
|
||||
"你中奖了",
|
||||
"恭喜你在抽奖贴 \"" + lp.getTitle() + "\" 中获奖"
|
||||
);
|
||||
try {
|
||||
emailSender.sendEmail(
|
||||
w.getEmail(),
|
||||
"你中奖了",
|
||||
"恭喜你在抽奖贴 \"" + lp.getTitle() + "\" 中获奖"
|
||||
);
|
||||
} catch (EmailSendException e) {
|
||||
log.warn("Failed to send lottery win email to {}: {}", w.getEmail(), e.getMessage());
|
||||
}
|
||||
}
|
||||
notificationService.createNotification(
|
||||
w,
|
||||
@@ -693,11 +698,19 @@ public class PostService {
|
||||
.getDisabledEmailNotificationTypes()
|
||||
.contains(NotificationType.LOTTERY_DRAW)
|
||||
) {
|
||||
emailSender.sendEmail(
|
||||
lp.getAuthor().getEmail(),
|
||||
"抽奖已开奖",
|
||||
"您的抽奖贴 \"" + lp.getTitle() + "\" 已开奖"
|
||||
);
|
||||
try {
|
||||
emailSender.sendEmail(
|
||||
lp.getAuthor().getEmail(),
|
||||
"抽奖已开奖",
|
||||
"您的抽奖贴 \"" + lp.getTitle() + "\" 已开奖"
|
||||
);
|
||||
} catch (EmailSendException e) {
|
||||
log.warn(
|
||||
"Failed to send lottery draw email to {}: {}",
|
||||
lp.getAuthor().getEmail(),
|
||||
e.getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
notificationService.createNotification(
|
||||
lp.getAuthor(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.openisle.service;
|
||||
|
||||
import com.openisle.exception.EmailSendException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -7,8 +8,9 @@ import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Service
|
||||
@@ -23,7 +25,6 @@ public class ResendEmailSender extends EmailSender {
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
@Override
|
||||
@Async("notificationExecutor")
|
||||
public void sendEmail(String to, String subject, String text) {
|
||||
String url = "https://api.resend.com/emails"; // hypothetical endpoint
|
||||
|
||||
@@ -38,6 +39,20 @@ public class ResendEmailSender extends EmailSender {
|
||||
body.put("from", "openisle <" + fromEmail + ">");
|
||||
|
||||
HttpEntity<Map<String, String>> entity = new HttpEntity<>(body, headers);
|
||||
restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
|
||||
try {
|
||||
ResponseEntity<String> response = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.POST,
|
||||
entity,
|
||||
String.class
|
||||
);
|
||||
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||
throw new EmailSendException(
|
||||
"Email service returned status " + response.getStatusCodeValue()
|
||||
);
|
||||
}
|
||||
} catch (RestClientException e) {
|
||||
throw new EmailSendException("Failed to send email: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,6 @@ public class UserService {
|
||||
* @param user
|
||||
*/
|
||||
public void sendVerifyMail(User user, VerifyType verifyType) {
|
||||
// 缓存验证码
|
||||
String code = genCode();
|
||||
String key;
|
||||
String subject;
|
||||
@@ -133,8 +132,9 @@ public class UserService {
|
||||
subject = "请填写验证码以重置密码(有效期为5分钟)";
|
||||
}
|
||||
|
||||
redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES); // 五分钟后验证码过期
|
||||
emailService.sendEmail(user.getEmail(), subject, content);
|
||||
// 邮件发送成功后再缓存验证码,避免发送失败时用户收不到但验证被要求
|
||||
redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES); // 五分钟后验证码过期
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user