EmailClient.java

  1. package no.nav.data.common.mail;

  2. import io.netty.handler.logging.LogLevel;
  3. import org.apache.logging.log4j.LogManager;
  4. import org.apache.logging.log4j.Logger;
  5. import org.springframework.http.client.reactive.ReactorClientHttpConnector;
  6. import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
  7. import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction;
  8. import org.springframework.stereotype.Component;
  9. import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
  10. import org.springframework.web.reactive.function.client.WebClient;
  11. import org.springframework.web.reactive.function.client.WebClientResponseException;
  12. import reactor.core.publisher.Mono;
  13. import reactor.netty.http.client.HttpClient;
  14. import reactor.netty.transport.logging.AdvancedByteBufFormat;
  15. import reactor.util.retry.Retry;

  16. import java.time.Duration;
  17. import java.util.List;

  18. @Component
  19. public class EmailClient {
  20.     public static final Logger logger = LogManager.getLogger(EmailClient.class);

  21.     private final WebClient webClient;
  22.     private final EmailProperties emailProperties;

  23.     public EmailClient(
  24.         OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager,
  25.         EmailProperties emailProperties
  26.     ) {
  27.         this.emailProperties = emailProperties;
  28.         var oAuth2Filter = new ServletOAuth2AuthorizedClientExchangeFilterFunction(oAuth2AuthorizedClientManager);
  29.         oAuth2Filter.setDefaultClientRegistrationId("email");


  30.         this.webClient = WebClient.builder()
  31.             .filter(oAuth2Filter)
  32.             .baseUrl(emailProperties.baseUrl())
  33.             .build();
  34.     }


  35.     public Mono<Void> sendEmail(MailTask mailTask) {
  36.         if (emailProperties.enabled()) {
  37.             var emailMessage = mapFrom(mailTask);

  38.             return webClient.post()
  39.                 .body(Mono.just(emailMessage), EmailMessage.class)
  40.                 .retrieve()
  41.                 .bodyToMono(Void.class)
  42.                 .retryWhen(defaultRetry(emailProperties.maxAttempts(), emailProperties.backoffDurationMillis()))
  43.                 .doOnError(WebClientResponseException.class, (WebClientResponseException webClientResponseException) -> {
  44.                     String errorMsg = String.format(
  45.                         "POST %s resulted in status %s with body %s",
  46.                         webClientResponseException.getRequest() != null ? webClientResponseException.getRequest().getURI() : "n/a",
  47.                         webClientResponseException.getStatusCode().value(),
  48.                         webClientResponseException.getResponseBodyAsString()
  49.                     );

  50.                     throw new EmailClientUnforseenException(errorMsg);
  51.                 });
  52.         } else {
  53.             logger.info("Email which would have been sent: {}", mailTask);
  54.             return Mono.empty();
  55.         }
  56.     }

  57.     private EmailMessage mapFrom(MailTask mailTask){
  58.         return new EmailMessage(
  59.                 mailTask.getSubject(),
  60.                 mailTask.getBody(),
  61.                 List.of(mailTask.getTo())
  62.         );
  63.     }

  64.     private Retry defaultRetry(Integer maxAttempts, Integer backoffDurationMillis) {
  65.         return Retry.backoff(maxAttempts, Duration.ofMillis(backoffDurationMillis)).jitter(0.75).filter(throwable -> {
  66.             if (throwable instanceof WebClientResponseException) {
  67.                 return ((WebClientResponseException) throwable).getStatusCode().is5xxServerError();
  68.             }
  69.             return false;
  70.         }).onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> {
  71.             Throwable throwable = retrySignal.failure();
  72.             if (throwable instanceof WebClientResponseException) {
  73.                 throw (WebClientResponseException) throwable;
  74.             }
  75.             throw new RuntimeException(throwable);
  76.         });
  77.     }

  78. }