JavaMailSender 로 같은 메일 보내기이 레슨의 SmtpClient 가 손으로 하는 일을 Spring 에서는 MimeMessageHelper 가 대신합니다.
@Autowired
private JavaMailSender mailSender;
public void sendReport(String to, byte[] csv) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper =
new MimeMessageHelper(message, true, "UTF-8"); // true=멀티파트
helper.setFrom("batch@company.co.kr");
helper.setTo(to);
helper.setSubject("9월 정산 리포트"); // 인코딩은 helper 가 처리
helper.setText("첨부한 리포트를 확인해 주세요.");
helper.addAttachment("정산리포트.csv", new ByteArrayResource(csv));
mailSender.send(message);
}RFC 2047 인코딩, multipart 조립, base64 변환을 라이브러리가 대신해 코드가 훨씬 짧습니다. 재시도·멱등키·폭주 억제 같은 정책은 이 레슨에서 다룬 대로 애플리케이션이 여전히 직접 챙겨야 합니다.
java.net.http.HttpClient 로 사내 메신저 웹훅에 JSON 을 POST 합니다. notifyAlert 뒤에 실제 전송을 붙이면 됩니다.
private static void sendWebhook(String webhookUrl, String text) throws Exception {
String json = "{\"text\":\"" + text.replace("\"", "\\\"") + "\"}";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(webhookUrl))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json, StandardCharsets.UTF_8))
.build();
client.send(request, HttpResponse.BodyHandlers.discarding());
}메일과 웹훅을 같은 notifyAlert 안에서 함께 호출하면, 억제 로직 하나로 두 채널 모두 폭주를 막습니다.
@Async 로 컨트롤러 스레드와 발송 스레드를 분리합니다. 자세한 스레드 풀 설정은 16 번 레슨을 참고합니다.
@Async("mailExecutor")
public void sendBulk(List<String> recipients, String subject, String body) {
for (List<String> chunk : partition(recipients, 150)) { // 150명씩 묶음
for (String to : chunk) {
trySend(to, subject, body); // 4xx 재시도·5xx 중단 포함
}
sleepQuietly(1000); // 릴레이 부하 분산
}
}컨트롤러는 이 메서드를 호출한 뒤 즉시 응답을 돌려주고, 실제 발송은 별도 스레드 풀에서 진행됩니다.