All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openmetadata.service.util.EmailUtil Maven / Gradle / Ivy

There is a newer version: 1.5.11
Show newest version
/*
 *  Copyright 2021 Collate
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  http://www.apache.org/licenses/LICENSE-2.0
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.openmetadata.service.util;

import static org.simplejavamail.api.mailer.config.TransportStrategy.SMTP;
import static org.simplejavamail.api.mailer.config.TransportStrategy.SMTPS;
import static org.simplejavamail.api.mailer.config.TransportStrategy.SMTP_TLS;

import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.IOException;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.openmetadata.common.utils.CommonUtil;
import org.openmetadata.schema.email.SmtpSettings;
import org.openmetadata.schema.entity.feed.Thread;
import org.openmetadata.schema.entity.teams.User;
import org.openmetadata.schema.settings.SettingsType;
import org.openmetadata.service.apps.bundles.changeEvent.email.EmailMessage;
import org.openmetadata.service.events.scheduled.template.DataInsightDescriptionAndOwnerTemplate;
import org.openmetadata.service.events.scheduled.template.DataInsightTotalAssetTemplate;
import org.openmetadata.service.resources.settings.SettingsCache;
import org.simplejavamail.api.email.Email;
import org.simplejavamail.api.email.EmailPopulatingBuilder;
import org.simplejavamail.api.mailer.Mailer;
import org.simplejavamail.api.mailer.config.TransportStrategy;
import org.simplejavamail.email.EmailBuilder;
import org.simplejavamail.mailer.MailerBuilder;

@Slf4j
public class EmailUtil {
  public static final String USERNAME = "userName";
  public static final String ENTITY = "entity";
  public static final String SUPPORT_URL = "supportUrl";
  // Email Verification
  private static final String EMAIL_VERIFICATION_SUBJECT =
      "%s: Verify your Email Address (Action Required)";
  public static final String EMAIL_VERIFICATION_LINKKEY = "userEmailTokenVerificationLink";
  public static final String EMAIL_VERIFICATION_TEMPLATE = "email-verification";
  // Password Reset Link
  private static final String PASSWORD_RESET_SUBJECT = "%s: Reset your Password";
  public static final String PASSWORD_RESET_LINKKEY = "userResetPasswordLink";
  public static final String EXPIRATION_TIME_KEY = "expirationTime";
  public static final String DEFAULT_EXPIRATION_TIME = "60";
  public static final String PASSWORD = "password";
  public static final String APPLICATION_LOGIN_LINK = "applicationLoginLink";
  public static final String PASSWORD_RESET_TEMPLATE_FILE = "reset-link";
  // Account Change Status
  private static final String ACCOUNT_STATUS_SUBJECT = "%s: Change in Account Status";
  public static final String ACTION_KEY = "action";
  public static final String ACTION_STATUS_KEY = "actionStatus";
  public static final String ACCOUNT_STATUS_TEMPLATE_FILE = "account-activity-change";
  private static final String INVITE_SUBJECT = "Welcome to %s";
  private static final String CHANGE_EVENT_UPDATE = "[%s] - Change Event Update from %s";

  private static final String TASK_SUBJECT = "%s : Task Assignment Notification";
  public static final String INVITE_RANDOM_PWD = "invite-randompwd";

  public static final String CHANGE_EVENT_TEMPLATE = "changeEvent";
  public static final String INVITE_CREATE_PWD = "invite-createPassword";
  public static final String TASK_NOTIFICATION_TEMPLATE = "taskAssignment";
  private static final String REPORT_SUBJECT = "%s: Data Insights Weekly - %s";
  public static final String DATA_INSIGHT_REPORT_TEMPLATE = "dataInsightReport";
  public static final String TEST_EMAIL_TEMPLATE = "testMail";
  public static final String TEST_EMAIL_SUBJECT = "%s : Test Email";
  private static SmtpSettings storedSmtpSettings;
  private static Mailer mailer;

  private static final String EMAIL_IGNORE_MSG =
      "Email was not sent to {} as SMTP setting is not enabled";

  private static TemplateProvider templateProvider;

  static {
    getSmtpSettings();
    initializeTemplateProvider();
  }

  // initialize template provider
  private static void initializeTemplateProvider() {
    templateProvider = new DefaultTemplateProvider();
  }

  private EmailUtil() {
    try {
      getSmtpSettings();
      initializeTemplateProvider();
      LOG.info("Email Util cache is initialized");
    } catch (Exception ex) {
      LOG.warn("[MAILER] Smtp Configurations are missing : Reason {} ", ex.getMessage(), ex);
    }
  }

  private static Mailer createMailer(SmtpSettings smtpServerSettings) {
    if (Boolean.TRUE.equals(smtpServerSettings.getEnableSmtpServer())) {
      TransportStrategy strategy =
          switch (smtpServerSettings.getTransportationStrategy()) {
            case SMTPS -> SMTPS;
            case SMTP_TLS -> SMTP_TLS;
            default -> SMTP;
          };
      String username =
          CommonUtil.nullOrEmpty(smtpServerSettings.getUsername())
              ? null
              : smtpServerSettings.getUsername();
      String password =
          CommonUtil.nullOrEmpty(smtpServerSettings.getPassword())
              ? null
              : smtpServerSettings.getPassword();
      return MailerBuilder.withSMTPServer(
              smtpServerSettings.getServerEndpoint(),
              smtpServerSettings.getServerPort(),
              username,
              password)
          .withTransportStrategy(strategy)
          .buildMailer();
    }
    return null;
  }

  public static void sendAccountStatus(User user, String action, String status)
      throws IOException, TemplateException {
    if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer())) {
      Map templatePopulator = new HashMap<>();
      templatePopulator.put(ENTITY, getEmailingEntity());
      templatePopulator.put(SUPPORT_URL, getSupportUrl());
      templatePopulator.put(USERNAME, user.getName());
      templatePopulator.put(ACTION_KEY, action);
      templatePopulator.put(ACTION_STATUS_KEY, status);
      sendMail(
          getAccountStatusChangeSubject(),
          templatePopulator,
          user.getEmail(),
          ACCOUNT_STATUS_TEMPLATE_FILE,
          true);
    } else {
      LOG.warn(EMAIL_IGNORE_MSG, user.getEmail());
    }
  }

  public static void sendEmailVerification(String emailVerificationLink, User user)
      throws IOException, TemplateException {
    if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer())) {
      Map templatePopulator = new HashMap<>();
      templatePopulator.put(ENTITY, getEmailingEntity());
      templatePopulator.put(SUPPORT_URL, getSupportUrl());
      templatePopulator.put(USERNAME, user.getName());
      templatePopulator.put(EMAIL_VERIFICATION_LINKKEY, emailVerificationLink);
      templatePopulator.put(EXPIRATION_TIME_KEY, "24");
      sendMail(
          getEmailVerificationSubject(),
          templatePopulator,
          user.getEmail(),
          EMAIL_VERIFICATION_TEMPLATE,
          true);
    } else {
      LOG.warn(EMAIL_IGNORE_MSG, user.getEmail());
    }
  }

  public static void sendPasswordResetLink(
      String passwordResetLink, User user, String subject, String templateFilePath)
      throws IOException, TemplateException {
    if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer())) {
      Map templatePopulator = new HashMap<>();
      templatePopulator.put(ENTITY, getEmailingEntity());
      templatePopulator.put(SUPPORT_URL, getSupportUrl());
      templatePopulator.put(USERNAME, user.getName());
      templatePopulator.put(PASSWORD_RESET_LINKKEY, passwordResetLink);
      templatePopulator.put(EXPIRATION_TIME_KEY, DEFAULT_EXPIRATION_TIME);

      sendMail(subject, templatePopulator, user.getEmail(), templateFilePath, true);
    } else {
      LOG.warn(EMAIL_IGNORE_MSG, user.getEmail());
    }
  }

  public static void sendTaskAssignmentNotificationToUser(
      String assigneeName,
      String email,
      String taskLink,
      Thread thread,
      String subject,
      String templateFilePath)
      throws IOException, TemplateException {
    if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer())) {
      Map templatePopulator = new HashMap<>();
      templatePopulator.put("assignee", assigneeName);
      templatePopulator.put("createdBy", thread.getCreatedBy());
      templatePopulator.put("taskName", thread.getMessage());
      templatePopulator.put("taskStatus", thread.getTask().getStatus().toString());
      templatePopulator.put("taskType", thread.getTask().getType().toString());
      templatePopulator.put("fieldOldValue", thread.getTask().getOldValue());
      templatePopulator.put("fieldNewValue", thread.getTask().getSuggestion());
      templatePopulator.put("taskLink", taskLink);

      sendMail(subject, templatePopulator, email, templateFilePath, true);
    } else {
      LOG.warn(EMAIL_IGNORE_MSG, email);
    }
  }

  public static void sendMail(
      String subject, Map model, String to, String templateName, boolean async)
      throws IOException, TemplateException {
    if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer())) {
      EmailPopulatingBuilder emailBuilder = EmailBuilder.startingBlank();
      emailBuilder.withSubject(subject);
      emailBuilder.to(to);
      emailBuilder.from(getSmtpSettings().getSenderMail());

      Template template = templateProvider.getTemplate(templateName);

      // write the freemarker output to a StringWriter
      StringWriter stringWriter = new StringWriter();
      template.process(model, stringWriter);
      String mailContent = stringWriter.toString();
      emailBuilder.withHTMLText(mailContent);
      sendMail(emailBuilder.buildEmail(), async);
    } else {
      LOG.warn(EMAIL_IGNORE_MSG, to);
    }
  }

  public static void sendMailToMultiple(
      String subject, Map model, Set to, String templateName)
      throws IOException, TemplateException {
    if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer())) {
      EmailPopulatingBuilder emailBuilder = EmailBuilder.startingBlank();
      emailBuilder.withSubject(subject);
      emailBuilder.toMultiple(to);
      emailBuilder.from(getSmtpSettings().getSenderMail());

      Template template = templateProvider.getTemplate(templateName);

      // write the freemarker output to a StringWriter
      StringWriter stringWriter = new StringWriter();
      template.process(model, stringWriter);
      String mailContent = stringWriter.toString();
      emailBuilder.withHTMLText(mailContent);
      sendMail(emailBuilder.buildEmail(), true);
    }
  }

  public static void sendMail(Email email, boolean async) {
    if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer()) && mailer != null) {
      mailer.sendMail(email, async);
    } else {
      LOG.error("Mailer is not initialized or Smtp is not Enabled.");
    }
  }

  public static void sendInviteMailToAdmin(User user, String pwd) {
    if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer())) {
      Map templatePopulator = new HashMap<>();
      templatePopulator.put(EmailUtil.ENTITY, EmailUtil.getEmailingEntity());
      templatePopulator.put(EmailUtil.SUPPORT_URL, EmailUtil.getSupportUrl());
      templatePopulator.put(EmailUtil.USERNAME, user.getName());
      templatePopulator.put(EmailUtil.PASSWORD, pwd);
      templatePopulator.put(EmailUtil.APPLICATION_LOGIN_LINK, EmailUtil.getOMUrl());
      try {
        EmailUtil.sendMail(
            EmailUtil.getEmailInviteSubject(),
            templatePopulator,
            user.getEmail(),
            EmailUtil.INVITE_RANDOM_PWD,
            true);
      } catch (Exception ex) {
        LOG.error(
            "Failed in sending Mail to user [{}]. Reason : {}", user.getEmail(), ex.getMessage());
      }
    } else {
      LOG.warn(EMAIL_IGNORE_MSG, user.getEmail());
    }
  }

  public static void sendChangeEventMail(
      String publisherName, String receiverMail, EmailMessage emailMessaged) {
    if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer())) {
      Map templatePopulator = new HashMap<>();
      templatePopulator.put(EmailUtil.USERNAME, receiverMail.split("@")[0]);
      templatePopulator.put("updatedBy", emailMessaged.getUpdatedBy());
      templatePopulator.put("entityUrl", emailMessaged.getEntityUrl());
      StringBuilder buff = new StringBuilder();
      for (String cmessage : emailMessaged.getChangeMessage()) {
        buff.append(cmessage);
        buff.append("\n");
      }
      templatePopulator.put("changeMessage", buff.toString());
      try {
        EmailUtil.sendMail(
            EmailUtil.getChangeEventTemplate(publisherName),
            templatePopulator,
            receiverMail,
            EmailUtil.CHANGE_EVENT_TEMPLATE,
            true);
      } catch (Exception ex) {
        LOG.error(
            "Failed in sending Mail to user [{}]. Reason : {}", receiverMail, ex.getMessage());
      }
    } else {
      LOG.warn(EMAIL_IGNORE_MSG, receiverMail);
    }
  }

  public static void sendDataInsightEmailNotificationToUser(
      Set emails,
      String startDate,
      String endDate,
      DataInsightTotalAssetTemplate totalAssetObj,
      DataInsightDescriptionAndOwnerTemplate descriptionObj,
      DataInsightDescriptionAndOwnerTemplate ownerShipObj,
      DataInsightDescriptionAndOwnerTemplate tierObj,
      String subject,
      String templateFilePath)
      throws IOException, TemplateException {
    if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer())) {
      Map templatePopulator = new HashMap<>();
      templatePopulator.put("startDate", startDate);
      templatePopulator.put("endDate", endDate);
      templatePopulator.put("totalAssetObj", totalAssetObj);
      templatePopulator.put("descriptionObj", descriptionObj);
      templatePopulator.put("ownershipObj", ownerShipObj);
      templatePopulator.put("tierObj", tierObj);
      templatePopulator.put(
          "viewReportUrl",
          String.format("%s/data-insights/data-assets", getSmtpSettings().getOpenMetadataUrl()));
      sendMailToMultiple(subject, templatePopulator, emails, templateFilePath);
    } else {
      LOG.warn(EMAIL_IGNORE_MSG, emails.toString());
    }
  }

  public static void sendTestEmail(String email, boolean async)
      throws IOException, TemplateException {
    if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer())) {
      Map templatePopulator = new HashMap<>();
      templatePopulator.put("userName", email.split("@")[0]);
      templatePopulator.put("entity", getSmtpSettings().getEmailingEntity());
      templatePopulator.put("supportUrl", getSmtpSettings().getSupportUrl());
      sendMail(getTestEmailSubject(), templatePopulator, email, TEST_EMAIL_TEMPLATE, async);
    } else {
      LOG.warn(EMAIL_IGNORE_MSG, email);
    }
  }

  public static void testConnection() {
    if (Boolean.TRUE.equals(getSmtpSettings().getEnableSmtpServer()) && mailer != null) {
      mailer.testConnection();
    } else {
      LOG.error("Mailer is not initialized or Smtp is not Enabled.");
    }
  }

  private static String getEmailVerificationSubject() {
    return String.format(EMAIL_VERIFICATION_SUBJECT, getSmtpSettings().getEmailingEntity());
  }

  public static String getPasswordResetSubject() {
    return String.format(PASSWORD_RESET_SUBJECT, getSmtpSettings().getEmailingEntity());
  }

  private static String getAccountStatusChangeSubject() {
    return String.format(ACCOUNT_STATUS_SUBJECT, getSmtpSettings().getEmailingEntity());
  }

  public static String getEmailInviteSubject() {
    return String.format(INVITE_SUBJECT, getSmtpSettings().getEmailingEntity());
  }

  public static String getChangeEventTemplate(String publisherName) {
    return String.format(CHANGE_EVENT_UPDATE, publisherName, getSmtpSettings().getEmailingEntity());
  }

  public static String getTaskAssignmentSubject() {
    return String.format(TASK_SUBJECT, getSmtpSettings().getEmailingEntity());
  }

  public static String getTestEmailSubject() {
    return String.format(TEST_EMAIL_SUBJECT, getSmtpSettings().getEmailingEntity());
  }

  public static String getDataInsightReportSubject() {
    return String.format(
        REPORT_SUBJECT,
        getSmtpSettings().getEmailingEntity(),
        new SimpleDateFormat("dd-MM-yy").format(new Date()));
  }

  public static String getEmailingEntity() {
    return getSmtpSettings().getEmailingEntity();
  }

  public static String getSupportUrl() {
    return getSmtpSettings().getSupportUrl();
  }

  public static String getOMUrl() {
    return getSmtpSettings().getOpenMetadataUrl();
  }

  public static SmtpSettings getSmtpSettings() {
    SmtpSettings emailConfig =
        SettingsCache.getSetting(SettingsType.EMAIL_CONFIGURATION, SmtpSettings.class);
    if (!emailConfig.equals(storedSmtpSettings)) {
      storedSmtpSettings = emailConfig;
      mailer = createMailer(emailConfig);
    }
    return emailConfig;
  }

  /**
   * Check if given email address is valid
   *
   * @param email email address
   * @return true if valid, false otherwise
   */
  public static Boolean isValidEmail(String email) {
    if (StringUtils.isBlank(email)) {
      return false;
    }
    return email.matches("^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$");
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy