如何在春季网络通量中被动发送电子邮件



我想在我的新春季应用程序中保持完全反应。因此,我使用web-flux/actor和ReactiveRepository与MongoDB。

你知道如何将java-mail被动地集成到技术堆栈中吗?还有其他选择吗?

为了发送电子邮件并且仍然不阻止,您可以在另一个线程中运行有关发送电子邮件的代码。如果您使用的是Spring WebFlux,则可以通过将用于发送电子邮件的代码包装在Mono(Reactor Library Publisher(的以下工厂方法中来轻松完成此操作。

Mono.fromCallable((

Mono.fromRunnable((

短代码

Mono.fromCallable(()-> sendEmail())
.subscribe();

其中sendEmail((是发送电子邮件的函数。

这也是文档中推荐的内容 - 如何包装同步、阻止调用?

长代码

以下是我在应用程序中使用的完整示例代码 -

Mono.fromCallable(() -> {
try {
MimeMessageHelper helper = new MimeMessageHelper(sender.createMimeMessage());
helper.setTo(to);
helper.setSubject(subject);
helper.setText(body);
sender.send(helper.getMimeMessage());
log.info("Email send successfully, subject {} , to {}", subject, to);
return true;
} catch (Exception e) {
log.warn("Failed to send email with subject {}, due to {}",subject,e.getMessage(), e});
return false;
}
)
.subscribe(result -> log.info("Mail sent {}", result));

当它是反应式堆栈时,永远不要忘记订阅:D

我也在寻找反应式SMTP客户端。

我设法找到了它;)

这是:https://github.com/HubSpot/NioSmtpClient

来自自述文件:

基于 Netty 的 Java 中的高性能 SMTP 客户端。该客户端经过良好测试并在 HubSpot 大量使用。

我已经在本地环境中验证了它,它真的是反应灵敏的! 但是,它使用completableFuture而不是Mono或Flux,因此有必要手动包装它。

总的来说,这个库看起来不错,但我认为如果作者提供一些可以简化 SDK 使用facade会更好。(无论如何,它是开源的,所以我们可以改进它(。

这里有一个例子,如何使用它(不要介意codeStyle,它只是一个示例(:

private static final String MESSAGE_DATA = "From: <sender@gmail.comrn" +
"To: <recipient@gmail.com>rn" +
"Subject: test mailrnrn" +
"Hello stackOverFlow!";
public static void main(String[] args) {
final SmtpSessionFactory smtpSessionFactory = createSmtpSessionFactory();
final SmtpSessionConfig smtpSessionConfig = SmtpSessionConfig.builder().remoteAddress(InetSocketAddress.createUnresolved("smtp.gmail.com", 587)).build();
Mono.fromFuture(smtpSessionFactory.connect(smtpSessionConfig))
.flatMap(connection -> doInSession(connection, req(EHLO, "gmail.com")))
.flatMap(connection -> Mono.fromFuture(connection.getSession().startTls()))
.flatMap(connection -> Mono.fromFuture(connection.getSession().authLogin("sender@gmail.com", "SomeStrongPasswordLike123456")))
.flatMap(connection -> doInSession(connection, req(MAIL, "FROM:<" + "sender@gmail.com" + ">")))
.flatMap(connection -> doInSession(connection, req(RCPT, "TO:<" + "recipient@gmail.com" + ">")))
.flatMap(connection -> doInSession(connection, req(DATA)))
.map(connection -> connection.getSession()
.send(MessageContent.of(Unpooled.wrappedBuffer(MESSAGE_DATA.getBytes(StandardCharsets.UTF_8)))))
.flatMap(Mono::fromFuture)
.flatMap(connection -> doInSession(connection, req(QUIT)))
.flatMap(connection -> Mono.fromFuture(connection.getSession().close()))
.block();
}
private static SmtpSessionFactory createSmtpSessionFactory() {
ThreadFactory threadFactory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("niosmtpclient-%d").build();
final SmtpSessionFactoryConfig config = SmtpSessionFactoryConfig.builder()
.eventLoopGroup(new NioEventLoopGroup(4, threadFactory))
.executor(Executors.newCachedThreadPool(threadFactory))
.build();
return new SmtpSessionFactory(config);
}
private static Mono<SmtpClientResponse> doInSession(SmtpClientResponse connection, SmtpRequest request) {
return Mono.fromFuture(connection.getSession().send(request));
}
private static SmtpRequest req(SmtpCommand command, CharSequence... arguments) {
return new DefaultSmtpRequest(command, arguments);
}

工作原理(一般(:

  1. 我们定义会话工厂(参见方法createSmtpSessionFactory(
  2. 我们打开与服务器的对话框(连接(
  3. 我们启动 TLS
  4. 我们使用我们的凭据进行身份验证
  5. 我们说发件人到服务器的电子邮件地址
  6. 我们说收件人到服务器的电子邮件地址
  7. 我们开始数据发送阶段
  8. 我们发送数据(数据必须遵循某种模式。从:。。。自:。。。主题:。。。。请参阅MESSAGE_DATA变量(
  9. 我们通知服务器我们正在完成对话。
  10. 我们结束会议

我找到并且仍在使用的唯一有用的非阻塞SMTP客户端是 https://vertx.io/docs/vertx-mail-client/java/
我甚至将它与spring-webflux和mongodb-driver-reactivestreams集成在一起,以便它们共享相同的Netty EventLoopGroup。

Mono.create<MailResult> { sink ->
mailClient.sendMail(email) { asyncResult ->
if (asyncResult.succeeded()) {
sink.success(asyncResult.result()
} else {
sink.error(asyncResult.cause()
}
}
}

使用Microsoft Graph API,并使用Microsoft的Exahnge服务器发送电子邮件怎么样 https://learn.microsoft.com/en-us/graph/use-the-api。 它不是原始问题的答案,但我想知道相同的概念可以在那里应用,或者是否有人使用此 API 有一些类似的东西。

我找到了解决方案。它使用外部服务(如Mailgun或SendGrid(的spring-boot-starter-data-mongodb-reactive和API。关键点是使用反应式Web客户端:

  1. 构建Web客户端实例(例如,使用Sendgrid API(:

    String endpoint = “https://api.sendgrid.com/v3/“;
    String sendUri = endpoint + “mail/send”;
    WebClient client = WebClient.builder().filter(…).clientConnector(new ReactorClientHttpConnector(HttpClient.create())).baseUrl(endpoint).build()
    
  2. 实现响应对象:

    @Data
    class Response implements Serializable {
    private boolean status;
    private String id;
    private String message;
    }
    @Data
    class NotificationStatusResponse implements Serializable {
    private LocalDateTime timestamp;
    private int status;
    private String message;
    private String traceId;
    private String responseId;
    private String providerResponseId;
    private String providerResponseMessage;
    }
    
  3. 发送您的信息 :

    public Mono<NotificationStatusResponse> send(NotificationMessage<EmailId> email) throws NotificationSendFailedException {
    Mono<NotificationStatusResponse> response = null;
    try {
    MultiValueMap<String, Object> formMap = new LinkedMultiValueMap<>(); // email parameters here: from, to, subject, html etc.
    response = client.post().uri(sendUri)
    .header("Authorization", "Basic " + “your credentials here”)
    .contentType(MediaType.MULTIPART_FORM_DATA).syncBody(formMap).retrieve()
    .bodyToMono(Response.class).map(this::getNotificationStatusResponse)
    .doOnSuccess(message -> log.debug("sent email successfully"))
    .doOnError((error -> log.error("email failed ", error)));
    } catch (WebClientException webClientException) {
    throw new NotificationSendFailedException("webClientException received", webClientException);
    }
    return response;
    NotificationStatusResponse getNotificationStatusResponse(Response response) {
    NotificationStatusResponse notificationStatusResponse = new NotificationStatusResponse();
    notificationStatusResponse.setStatus(200);
    notificationStatusResponse.setTimestamp(LocalDateTime.now());
    notificationStatusResponse.setProviderResponseId(response.getId());
    notificationStatusResponse.setProviderResponseMessage(response.getMessage());
    return notificationStatusResponse;
    }
    }
    

相关内容

最新更新