MailService.java

package com.nonononoki.alovoa.service;

import com.nonononoki.alovoa.Tools;
import com.nonononoki.alovoa.entity.User;
import com.nonononoki.alovoa.entity.user.Conversation;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

@Service
public class MailService {

    private static String UUID_FORMAT = "<br><br><br><p style=\"color:#848484\">%s</p>";

    @Value("${spring.mail.username}")
    private String defaultFrom;

    @Autowired
    private MessageSource messageSource;

    @Autowired
    private JavaMailSender mailSender;

    @Value("${app.name}")
    private String appName;

    @Value("${app.domain}")
    private String appDomain;

    @Value("${app.url.front-end}")
    private String appFrontend;

    @Value("${app.company.name}")
    private String companyName;

    private static final Logger logger = LoggerFactory.getLogger(MailService.class);

    public boolean sendMail(String to, String from, String subject, String body) {
        try {
            MimeMessage mimeMessage = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, StandardCharsets.UTF_8.name());
            helper.setFrom(from);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(getEmailText(body), true);
            mailSender.send(mimeMessage);
            return true;
        } catch (Exception e) {
            logger.error(e.getMessage());
            return false;
        }
    }

    public void sendAdminMail(String to, String subject, String body) {
        sendMail(to, defaultFrom, subject, body);
    }

    public void sendAdminMailAll(String subject, String body, List<User> users) throws MessagingException, IOException {
        boolean failed = false;
        for (User u : users) {
            if (!sendMail(u.getEmail(), defaultFrom, subject, body)) {
                failed = true;
            }
        }
        if (failed) {
            throw new MessagingException("One or more emails failed to send. Please check your logs.");
        }
    }

    private String getEmailText(String body) throws IOException {
        String template = Tools.getResourceText("static/templates/email.html");
        String hrefWebsite = appDomain + "/";
        String hrefDonate = appDomain + "/donate-list";
        String imgSrc = Tools.imageToB64("static/img/mail_icon.jpg", "jpeg");
        String text = template.replace("MAIL_BODY", body);
        text = text.replace("COMPANY_NAME", companyName);
        text = text.replace("SRC_IMAGE", imgSrc);
        text = text.replace("HREF_APP_FRONTEND", appFrontend);
        text = text.replace("HREF_WEBSITE", hrefWebsite);
        text = text.replace("HREF_DONATE", hrefDonate);

        return text;
    }

    public void sendRegistrationMail(User user) throws MessagingException, IOException {
        Locale locale = Tools.getUserLocale(user);
        String subject = messageSource.getMessage("backend.mail.register.subject", new String[]{appName}, "",
                locale);
        String body = messageSource.getMessage("backend.mail.register.body",
                new String[]{user.getFirstName(), appName, appDomain, user.getRegisterToken().getContent()}, "",
                locale);
        body += String.format(UUID_FORMAT, user.getUuid());
        sendMail(user.getEmail(), defaultFrom, subject, body);
    }

    public void sendPasswordResetMail(User user) throws MessagingException, IOException {
        Locale locale = Tools.getUserLocale(user);
        String subject = messageSource.getMessage("backend.mail.password-reset.subject", new String[]{appName},
                locale);
        String body = messageSource.getMessage("backend.mail.password-reset.body",
                new String[]{user.getFirstName(), appName, appDomain, user.getPasswordToken().getContent()}, locale);
        sendMail(user.getEmail(), defaultFrom, subject, body);
    }

    public void sendAccountDeleteRequest(User user) throws MessagingException, IOException {
        Locale locale = Tools.getUserLocale(user);
        String subject = messageSource.getMessage("backend.mail.account-delete-request.subject",
                new String[]{appName}, locale);
        String body = messageSource.getMessage("backend.mail.account-delete-request.body",
                new String[]{user.getFirstName(), appName, appDomain, user.getDeleteToken().getContent()}, "",
                locale);
        sendMail(user.getEmail(), defaultFrom, subject, body);
    }

    public void sendAccountDeleteConfirm(User user) throws MessagingException, IOException {
        Locale locale = Tools.getUserLocale(user);
        String subject = messageSource.getMessage("backend.mail.account-delete-confirm.subject",
                new String[]{appName}, locale);
        String body = messageSource.getMessage("backend.mail.account-delete-confirm.body",
                new String[]{user.getFirstName(), appName}, locale);
        sendMail(user.getEmail(), defaultFrom, subject, body);
    }

    public void sendAccountConfirmed(User user) throws MessagingException, IOException {
        Locale locale = Tools.getUserLocale(user);
        String subject = messageSource.getMessage("backend.mail.account-confirmed.subject", new String[]{appName},
                locale);
        String body = messageSource.getMessage("backend.mail.account-confirmed.body",
                new String[]{user.getFirstName(), appName, appDomain}, "", locale);
        sendMail(user.getEmail(), defaultFrom, subject, body);
    }

    public void sendLikeNotificationMail(User user) {
        Locale locale = Tools.getUserLocale(user);
        String subject = messageSource.getMessage("backend.mail.like.subject", new String[]{}, locale);
        String body = messageSource.getMessage("backend.mail.like.body", new String[]{user.getFirstName()}, locale);
        sendMail(user.getEmail(), defaultFrom, subject, body);
    }

    public void sendMatchNotificationMail(User user) {
        Locale locale = Tools.getUserLocale(user);
        String subject = messageSource.getMessage("backend.mail.match.subject", new String[]{}, locale);
        String body = messageSource.getMessage("backend.mail.match.body", new String[]{user.getFirstName()}, locale);
        sendMail(user.getEmail(), defaultFrom, subject, body);
    }

    public boolean sendChatNotificationMail(User user, User currUser, String message, Conversation conversation) {
        //only send mail notification if the previous message was NOT from current user in order to avoid spam
        if (conversation.getMessages().size() <= 1 ||
                !Objects.equals(conversation.getMessages().get(conversation.getMessages().size() - 2).getUserFrom().getId(), currUser.getId())) {
            Locale locale = Tools.getUserLocale(user);
            String subject = messageSource.getMessage("backend.mail.chat.subject", new String[]{}, locale);
            String body = messageSource.getMessage("backend.mail.chat.body", new String[]{currUser.getFirstName(), user.getFirstName(), message}, locale);
            sendMail(defaultFrom, user.getEmail(), subject, body);
            return true;
        }
        return false;
    }
}