How to support list of standby smtp servers?

167 Views Asked by At

Currently our code for sending email messages looks like this:

@Override
public SendEmailResponse sendEmail(DtoEmailMessage dtoEmailMessage) {
    try {
        MimeMessage mimeMessage = mimeMessageCreator.createMessage(dtoEmailMessage);
        javaMailSender.send(mimeMessage);
        return SendEmailResponse.ok(channelEmailMessage.getEmailNotification().getTo(), mimeMessage.getMessageID());
    } catch (UnsupportedEncodingException | MessagingException | RuntimeException e) {
       ...
    }
}

What has to be improved ?

I want to support a list of reserved smtp servers. So in case if server_1 is failed for 2 or 3 times I wan to try with server_2. In case if server_2 is failed - server_3 is used etc.

I know about spring-retry and spring-hystrix but looks like they are not applicable for current task.

Is there any production ready solution for my task or it is better implement it on my own?

3

There are 3 best solutions below

0
Üsame Tekinkaya On

It would better to handle multiple SMTP hosts managed by a load balancer however you can manage in your application code as well.

public class EmailService {
    private static final int MAX_RETRIES = 3;
    private final List<String> smtpServers;

    public EmailService(List<String> smtpServers) {
        this.smtpServers = smtpServers;
    }

    @Override
    public SendEmailResponse sendEmail(DtoEmailMessage dtoEmailMessage) {
        for (String smtpServer : smtpServers) {
            try {
                // create the email message
                MimeMessage mimeMessage = mimeMessageCreator.createMessage(dtoEmailMessage);
                JavaMailSenderImpl mailSender = new JavaMailSenderImpl()
                mailSender.setHostName(smtpServer);
                mailSender.setPort(587);
                mailSender.setUsername("myusername");
                mailSender.setPassword("mypassword");
                // send the email message with automatic retry
                RetryExecutor executor = new RetryExecutor()
                    .withMaxRetries(MAX_RETRIES)
                    .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS));
                executor.retry(() -> mailSender.send(mimeMessage));

                return SendEmailResponse.ok(channelEmailMessage.getEmailNotification().getTo(), mimeMessage.getMessageID());
            } catch (EmailException e) {
                // log the error and try the next SMTP server
            }
        }
        // all SMTP servers failed
        throw new RuntimeException("Failed to send email message to any SMTP server");
    }
}

0
Alexander  Kutsy On

Better to use SMTP Connection Pool with all pool features (https://github.com/nithril/smtp-connection-pool).

0
Zakariae BEN ALLAL On

For me you have to implement circuit breaker design pattern.

I recommandé resilience4j :https://resilience4j.readme.io/docs.

Hystrix it no more supported, it's deprecated.