diff --git a/obp-api/pom.xml b/obp-api/pom.xml index 1227da21a..92bf9c7df 100644 --- a/obp-api/pom.xml +++ b/obp-api/pom.xml @@ -101,6 +101,12 @@ commons-text 1.10.0 + + + org.apache.commons + commons-email + 1.5 + org.postgresql postgresql diff --git a/obp-api/src/main/scala/code/api/util/CommonsEmailWrapper.scala b/obp-api/src/main/scala/code/api/util/CommonsEmailWrapper.scala new file mode 100644 index 000000000..bd695b819 --- /dev/null +++ b/obp-api/src/main/scala/code/api/util/CommonsEmailWrapper.scala @@ -0,0 +1,201 @@ +package code.api.util + +import org.apache.commons.mail.{Email, SimpleEmail, HtmlEmail, MultiPartEmail, EmailAttachment, DefaultAuthenticator} +import java.io.File +import java.net.URL +import code.util.Helper.MdcLoggable +import net.liftweb.common.{Box, Empty, Full} +import net.liftweb.util.Helpers.now + +/** + * Apache Commons Email Wrapper for OBP-API + * This wrapper provides a simple interface to send emails using Apache Commons Email + * instead of Lift Web's Mailer + */ +object CommonsEmailWrapper extends MdcLoggable { + + /** + * Email configuration case class + */ + case class EmailConfig( + smtpHost: String, + smtpPort: Int, + username: String, + password: String, + useTLS: Boolean = true, + useSSL: Boolean = false, + debug: Boolean = false + ) + + /** + * Email content case class + */ + case class EmailContent( + from: String, + to: List[String], + cc: List[String] = List.empty, + bcc: List[String] = List.empty, + subject: String, + textContent: Option[String] = None, + htmlContent: Option[String] = None, + attachments: List[EmailAttachment] = List.empty + ) + + /** + * Send simple text email + */ + def sendTextEmail(config: EmailConfig, content: EmailContent): Box[String] = { + try { + logger.info(s"Sending text email from ${content.from} to ${content.to.mkString(", ")}") + + val email = new SimpleEmail() + configureEmail(email, config, content) + + // Set text content + content.textContent match { + case Some(text) => email.setMsg(text) + case None => email.setMsg("") + } + + val messageId = email.send() + logger.info(s"Email sent successfully with Message-ID: $messageId") + Full(messageId) + } catch { + case e: Exception => + logger.error(s"Failed to send text email: ${e.getMessage}", e) + Empty + } + } + + /** + * Send HTML email + */ + def sendHtmlEmail(config: EmailConfig, content: EmailContent): Box[String] = { + try { + logger.info(s"Sending HTML email from ${content.from} to ${content.to.mkString(", ")}") + + val email = new HtmlEmail() + configureEmail(email, config, content) + + // Set HTML content + content.htmlContent match { + case Some(html) => email.setHtmlMsg(html) + case None => email.setHtmlMsg("No content") + } + + // Set text content as fallback + content.textContent.foreach(email.setTextMsg) + + val messageId = email.send() + logger.info(s"HTML email sent successfully with Message-ID: $messageId") + Full(messageId) + } catch { + case e: Exception => + logger.error(s"Failed to send HTML email: ${e.getMessage}", e) + Empty + } + } + + /** + * Send email with attachments + */ + def sendEmailWithAttachments(config: EmailConfig, content: EmailContent): Box[String] = { + try { + logger.info(s"Sending email with attachments from ${content.from} to ${content.to.mkString(", ")}") + + val email = new MultiPartEmail() + configureEmail(email, config, content) + + // Set text content + content.textContent.foreach(email.setMsg) + + // Add attachments + content.attachments.foreach(email.attach) + + val messageId = email.send() + logger.info(s"Email with attachments sent successfully with Message-ID: $messageId") + Full(messageId) + } catch { + case e: Exception => + logger.error(s"Failed to send email with attachments: ${e.getMessage}", e) + Empty + } + } + + /** + * Configure email with common settings + */ + private def configureEmail(email: Email, config: EmailConfig, content: EmailContent): Unit = { + // SMTP Configuration + email.setHostName(config.smtpHost) + email.setSmtpPort(config.smtpPort) + email.setAuthenticator(new DefaultAuthenticator(config.username, config.password)) + email.setSSLOnConnect(config.useSSL) + email.setStartTLSEnabled(config.useTLS) + email.setDebug(config.debug) + + // Set charset + email.setCharset("UTF-8") + + // Set sender + email.setFrom(content.from) + + // Set recipients + content.to.foreach(email.addTo) + content.cc.foreach(email.addCc) + content.bcc.foreach(email.addBcc) + + // Set subject + email.setSubject(content.subject) + } + + /** + * Create email attachment from file + */ + def createFileAttachment(filePath: String, name: Option[String] = None): EmailAttachment = { + val attachment = new EmailAttachment() + attachment.setPath(filePath) + attachment.setDisposition(EmailAttachment.ATTACHMENT) + name.foreach(attachment.setName) + attachment + } + + /** + * Create email attachment from URL + */ + def createUrlAttachment(url: String, name: String): EmailAttachment = { + val attachment = new EmailAttachment() + attachment.setURL(new URL(url)) + attachment.setDisposition(EmailAttachment.ATTACHMENT) + attachment.setName(name) + attachment + } + + /** + * Test MailHog configuration, this for testing + */ + def testMailHogConfig(): Unit = { + val config = EmailConfig( + smtpHost = "localhost", + smtpPort = 1025, + username = "", + password = "", + useTLS = false, + debug = true + ) + + val content = EmailContent( + from = "test@localhost", + to = List("receive@mailhog.local"), + subject = "Test MailHog with Apache Commons Email", + textContent = Some("This is a test email sent to MailHog using Apache Commons Email wrapper.") + ) + + logger.info("Testing MailHog configuration with Apache Commons Email...") + + sendTextEmail(config, content) match { + case Full(messageId) => logger.info(s"MailHog email sent successfully: $messageId") + case Empty => logger.error("Failed to send MailHog email") + } + } +} \ No newline at end of file diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index c2e98117b..70ae47c69 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -83,8 +83,8 @@ import net.liftweb.json.JsonDSL._ import net.liftweb.json.Serialization.write import net.liftweb.json._ import net.liftweb.util.Helpers.{now, tryo} -import net.liftweb.util.Mailer.{From, PlainMailBodyType, Subject, To, XHTMLMailBodyType} -import net.liftweb.util.{Helpers, Mailer, StringHelpers} +import net.liftweb.util.{Helpers, StringHelpers} +import code.api.util.CommonsEmailWrapper._ import org.apache.commons.lang3.StringUtils import java.net.URLEncoder @@ -3368,7 +3368,30 @@ trait APIMethods400 extends MdcLoggable { .replace(WebUIPlaceholder.activateYourAccount, link) logger.debug(s"customHtmlText: ${customHtmlText}") logger.debug(s"Before send user invitation by email. Purpose: ${UserInvitationPurpose.DEVELOPER}") - Mailer.sendMail(From(from), Subject(subject), To(invitation.email), PlainMailBodyType(customText), XHTMLMailBodyType(XML.loadString(customHtmlText))) + + // Use Apache Commons Email wrapper instead of Lift Mailer + val emailConfig = EmailConfig( + smtpHost = APIUtil.getPropsValue("mail.smtp.host", "localhost"), + smtpPort = APIUtil.getPropsValue("mail.smtp.port", "1025").toInt, + username = APIUtil.getPropsValue("mail.smtp.user", ""), + password = APIUtil.getPropsValue("mail.smtp.password", ""), + useTLS = APIUtil.getPropsValue("mail.smtp.starttls.enable", "false").toBoolean, + debug = APIUtil.getPropsValue("mail.debug", "false").toBoolean + ) + + val emailContent = EmailContent( + from = from, + to = List(invitation.email), + subject = subject, + textContent = Some(customText), + htmlContent = Some(customHtmlText) + ) + + sendHtmlEmail(emailConfig, emailContent) match { + case Full(messageId) => logger.debug(s"Email sent successfully with Message-ID: $messageId") + case Empty => logger.error("Failed to send user invitation email") + } + logger.debug(s"After send user invitation by email. Purpose: ${UserInvitationPurpose.DEVELOPER}") } else { val subject = getWebUiPropsValue("webui_customer_user_invitation_email_subject", "Welcome to the API Playground") @@ -3380,7 +3403,30 @@ trait APIMethods400 extends MdcLoggable { .replace(WebUIPlaceholder.activateYourAccount, link) logger.debug(s"customHtmlText: ${customHtmlText}") logger.debug(s"Before send user invitation by email.") - Mailer.sendMail(From(from), Subject(subject), To(invitation.email), PlainMailBodyType(customText), XHTMLMailBodyType(XML.loadString(customHtmlText))) + + // Use Apache Commons Email wrapper instead of Lift Mailer + val emailConfig = EmailConfig( + smtpHost = APIUtil.getPropsValue("mail.smtp.host", "localhost"), + smtpPort = APIUtil.getPropsValue("mail.smtp.port", "1025").toInt, + username = APIUtil.getPropsValue("mail.smtp.user", ""), + password = APIUtil.getPropsValue("mail.smtp.password", ""), + useTLS = APIUtil.getPropsValue("mail.smtp.starttls.enable", "false").toBoolean, + debug = APIUtil.getPropsValue("mail.debug", "false").toBoolean + ) + + val emailContent = EmailContent( + from = from, + to = List(invitation.email), + subject = subject, + textContent = Some(customText), + htmlContent = Some(customHtmlText) + ) + + sendHtmlEmail(emailConfig, emailContent) match { + case Full(messageId) => logger.debug(s"Email sent successfully with Message-ID: $messageId") + case Empty => logger.error("Failed to send user invitation email") + } + logger.debug(s"After send user invitation by email.") } (JSONFactory400.createUserInvitationJson(invitation), HttpCode.`201`(callContext))