com.sun.activation
jakarta.activation
diff --git a/obp-api/src/main/scala/code/api/util/CommonsEmailWrapper.scala b/obp-api/src/main/scala/code/api/util/CommonsEmailWrapper.scala
index 3b57e97470..f4cf89b56e 100644
--- a/obp-api/src/main/scala/code/api/util/CommonsEmailWrapper.scala
+++ b/obp-api/src/main/scala/code/api/util/CommonsEmailWrapper.scala
@@ -1,21 +1,21 @@
package code.api.util
import code.util.Helper.MdcLoggable
+import jakarta.activation.{DataHandler, FileDataSource, URLDataSource}
+import jakarta.mail._
+import jakarta.mail.internet._
import net.liftweb.common.{Box, Empty, Full}
-import org.apache.commons.mail._
+import java.io.File
import java.net.URL
+import java.util.Properties
/**
- * 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
+ * Jakarta Mail Wrapper for OBP-API
+ * This wrapper provides a simple interface to send emails using Jakarta Mail
*/
object CommonsEmailWrapper extends MdcLoggable {
- /**
- * Email configuration case class
- */
case class EmailConfig(
smtpHost: String,
smtpPort: Int,
@@ -24,12 +24,9 @@ object CommonsEmailWrapper extends MdcLoggable {
useTLS: Boolean = true,
useSSL: Boolean = false,
debug: Boolean = false,
- tlsProtocols: String = "TLSv1.2" // TLS protocols to use
+ tlsProtocols: String = "TLSv1.2"
)
- /**
- * Email content case class
- */
case class EmailContent(
from: String,
to: List[String],
@@ -41,9 +38,12 @@ object CommonsEmailWrapper extends MdcLoggable {
attachments: List[EmailAttachment] = List.empty
)
- /**
- * Get default email configuration from OBP-API properties
- */
+ case class EmailAttachment(
+ filePath: Option[String] = None,
+ url: Option[String] = None,
+ name: Option[String] = None
+ )
+
def getDefaultEmailConfig(): EmailConfig = {
EmailConfig(
smtpHost = APIUtil.getPropsValue("mail.smtp.host", "localhost"),
@@ -57,46 +57,27 @@ object CommonsEmailWrapper extends MdcLoggable {
)
}
- /**
- * Send simple text email with default configuration
- */
def sendTextEmail(content: EmailContent): Box[String] = {
sendTextEmail(getDefaultEmailConfig(), content)
}
- /**
- * Send HTML email with default configuration
- */
def sendHtmlEmail(content: EmailContent): Box[String] = {
sendHtmlEmail(getDefaultEmailConfig(), content)
}
- /**
- * Send email with attachments using default configuration
- */
def sendEmailWithAttachments(content: EmailContent): Box[String] = {
sendEmailWithAttachments(getDefaultEmailConfig(), content)
}
- /**
- * 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)
+ logger.debug(s"Sending text email from ${content.from} to ${content.to.mkString(", ")}")
+ val session = createSession(config)
+ val message = new MimeMessage(session)
+ setCommonHeaders(message, content)
+ message.setText(content.textContent.getOrElse(""), "UTF-8")
+ Transport.send(message)
+ Full(message.getMessageID)
} catch {
case e: Exception =>
logger.error(s"Failed to send text email: ${e.getMessage}", e)
@@ -104,28 +85,28 @@ object CommonsEmailWrapper extends MdcLoggable {
}
}
- /**
- * 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")
+ logger.debug(s"Sending HTML email from ${content.from} to ${content.to.mkString(", ")}")
+ val session = createSession(config)
+ val message = new MimeMessage(session)
+ setCommonHeaders(message, content)
+ val multipart = {
+ new MimeMultipart("alternative")
+ }
+ content.textContent.foreach { text =>
+ val textPart = new MimeBodyPart()
+ textPart.setText(text, "UTF-8")
+ multipart.addBodyPart(textPart)
+ }
+ content.htmlContent.foreach { html =>
+ val htmlPart = new MimeBodyPart()
+ htmlPart.setContent(html, "text/html; charset=UTF-8")
+ multipart.addBodyPart(htmlPart)
}
-
- // 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)
+ message.setContent(multipart)
+ Transport.send(message)
+ Full(message.getMessageID)
} catch {
case e: Exception =>
logger.error(s"Failed to send HTML email: ${e.getMessage}", e)
@@ -133,25 +114,45 @@ object CommonsEmailWrapper extends MdcLoggable {
}
}
- /**
- * 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)
-
+ logger.debug(s"Sending email with attachments from ${content.from} to ${content.to.mkString(", ")}")
+ val session = createSession(config)
+ val message = new MimeMessage(session)
+ setCommonHeaders(message, content)
+ val multipart = new MimeMultipart()
+ // Add text or HTML part
+ (content.htmlContent, content.textContent) match {
+ case (Some(html), _) =>
+ val htmlPart = new MimeBodyPart()
+ htmlPart.setContent(html, "text/html; charset=UTF-8")
+ multipart.addBodyPart(htmlPart)
+ case (None, Some(text)) =>
+ val textPart = new MimeBodyPart()
+ textPart.setText(text, "UTF-8")
+ multipart.addBodyPart(textPart)
+ case _ =>
+ val textPart = new MimeBodyPart()
+ textPart.setText("", "UTF-8")
+ multipart.addBodyPart(textPart)
+ }
// 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)
+ content.attachments.foreach { att =>
+ val attachPart = new MimeBodyPart()
+ if (att.filePath.isDefined) {
+ val fds = new FileDataSource(new File(att.filePath.get))
+ attachPart.setDataHandler(new DataHandler(fds))
+ attachPart.setFileName(att.name.getOrElse(new File(att.filePath.get).getName))
+ } else if (att.url.isDefined) {
+ val uds = new URLDataSource(new URL(att.url.get))
+ attachPart.setDataHandler(new DataHandler(uds))
+ attachPart.setFileName(att.name.getOrElse(att.url.get.split('/').last))
+ }
+ multipart.addBodyPart(attachPart)
+ }
+ message.setContent(multipart)
+ Transport.send(message)
+ Full(message.getMessageID)
} catch {
case e: Exception =>
logger.error(s"Failed to send email with attachments: ${e.getMessage}", e)
@@ -159,54 +160,34 @@ object CommonsEmailWrapper extends MdcLoggable {
}
}
- /**
- * 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)
- email.getMailSession.getProperties.setProperty("mail.smtp.ssl.protocols", config.tlsProtocols)
-
- // 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)
+ private def createSession(config: EmailConfig): Session = {
+ val props = new Properties()
+ props.put("mail.smtp.host", config.smtpHost)
+ props.put("mail.smtp.port", config.smtpPort.toString)
+ props.put("mail.smtp.auth", "true")
+ props.put("mail.smtp.starttls.enable", config.useTLS.toString)
+ props.put("mail.smtp.ssl.enable", config.useSSL.toString)
+ props.put("mail.debug", config.debug.toString)
+ props.put("mail.smtp.ssl.protocols", config.tlsProtocols)
+ val authenticator = new Authenticator() {
+ override def getPasswordAuthentication: PasswordAuthentication =
+ new PasswordAuthentication(config.username, config.password)
+ }
+ Session.getInstance(props, authenticator)
}
- /**
- * 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
+ private def setCommonHeaders(message: MimeMessage, content: EmailContent): Unit = {
+ message.setFrom(new InternetAddress(content.from))
+ content.to.foreach(addr => message.addRecipient(Message.RecipientType.TO, new InternetAddress(addr)))
+ content.cc.foreach(addr => message.addRecipient(Message.RecipientType.CC, new InternetAddress(addr)))
+ content.bcc.foreach(addr => message.addRecipient(Message.RecipientType.BCC, new InternetAddress(addr)))
+ message.setSubject(content.subject, "UTF-8")
}
- /**
- * 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
- }
+ def createFileAttachment(filePath: String, name: Option[String] = None): EmailAttachment =
+ EmailAttachment(filePath = Some(filePath), url = None, name = name)
+
+ def createUrlAttachment(url: String, name: String): EmailAttachment =
+ EmailAttachment(filePath = None, url = Some(url), name = Some(name))
}
\ No newline at end of file
diff --git a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala
index daed891795..0d9334ff58 100644
--- a/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala
+++ b/obp-api/src/main/scala/code/model/dataAccess/AuthUser.scala
@@ -589,24 +589,14 @@ import net.liftweb.util.Helpers._
*/
override def sendPasswordReset(name: String) {
findAuthUserByUsernameLocallyLegacy(name).toList ::: findUsersByEmailLocally(name) map {
- // reason of case parameter name is "u" instead of "user": trait AuthUser have constant mumber name is "user"
- // So if the follow case paramter name is "user" will cause compile warnings
case u if u.validated_? =>
u.resetUniqueId().save
- //NOTE: here, if server_mode = portal, so we need modify the resetLink to portal_hostname, then developer can get proper response..
val resetPasswordLinkProps = Constant.HostName
val resetPasswordLink = APIUtil.getPropsValue("portal_hostname", resetPasswordLinkProps)+
passwordResetPath.mkString("/", "/", "/")+urlEncode(u.getUniqueId())
- logger.error("222222222222222222222222222222222222222444:"+classOf[javax.activation.DataSource].getProtectionDomain.getCodeSource)
- // Use Apache Commons Email wrapper instead of Lift Mailer
- val emailBodies = generateResetEmailBodies(u, resetPasswordLink)
-
- // Extract text and HTML content from email bodies
- val textContent = emailBodies.find(_.isInstanceOf[net.liftweb.util.Mailer.PlainMailBodyType])
- .map(_.asInstanceOf[net.liftweb.util.Mailer.PlainMailBodyType].toString.replace("PlainMailBodyType(", "").replace(")", ""))
- val htmlContent = emailBodies.find(_.isInstanceOf[net.liftweb.util.Mailer.XHTMLMailBodyType])
- .map(_.asInstanceOf[net.liftweb.util.Mailer.XHTMLMailBodyType].toString.replace("XHTMLMailBodyType(", "").replace(")", ""))
-
+ // Directly generate content using JakartaMail/CommonsEmailWrapper
+ val textContent = Some(s"Please use the following link to reset your password: $resetPasswordLink")
+ val htmlContent = Some(s"Please use the following link to reset your password:
$resetPasswordLink
")
val emailContent = EmailContent(
from = emailFrom,
to = List(u.getEmail),
@@ -628,8 +618,6 @@ import net.liftweb.util.Helpers._
case u =>
sendValidationEmail(u)
}
- // In order to prevent any leakage of information we use the same message for all cases
- // Note: Individual success/error messages are now handled in the email sending logic above
}
override def lostPasswordXhtml = {
@@ -661,22 +649,10 @@ import net.liftweb.util.Helpers._
* Overridden to use the hostname set in the props file
*/
override def sendValidationEmail(user: TheUserType) {
- val resetLink = Constant.HostName+"/"+validateUserPath.mkString("/")+
- "/"+urlEncode(user.getUniqueId())
-
+ val resetLink = Constant.HostName+"/"+validateUserPath.mkString("/")+"/"+urlEncode(user.getUniqueId())
val email: String = user.getEmail
-
- val msgXml = signupMailBody(user, resetLink)
-
- // Use Apache Commons Email wrapper instead of Lift Mailer
- val emailBodies: List[Mailer.MailBodyType] = generateValidationEmailBodies(user, resetLink)
-
- // Extract text and HTML content from email bodies
- val textContent = emailBodies.find(_.isInstanceOf[net.liftweb.util.Mailer.PlainMailBodyType])
- .map(_.asInstanceOf[net.liftweb.util.Mailer.PlainMailBodyType].toString.replace("PlainMailBodyType(", "").replace(")", ""))
- val htmlContent = emailBodies.find(_.isInstanceOf[net.liftweb.util.Mailer.XHTMLMailBodyType])
- .map(_.asInstanceOf[net.liftweb.util.Mailer.XHTMLMailBodyType].toString.replace("XHTMLMailBodyType(", "").replace(")", ""))
-
+ val textContent = Some(s"Welcome! Please validate your account by clicking the following link: $resetLink")
+ val htmlContent = Some(s"Welcome! Please validate your account by clicking the following link:
$resetLink
")
val emailContent = EmailContent(
from = emailFrom,
to = List(user.getEmail),
@@ -685,7 +661,6 @@ import net.liftweb.util.Helpers._
textContent = textContent,
htmlContent = htmlContent
)
-
sendHtmlEmail(emailContent) match {
case Full(messageId) =>
logger.debug(s"Validation email sent successfully with Message-ID: $messageId")
diff --git a/obp-commons/pom.xml b/obp-commons/pom.xml
index c7f68bad46..b41909faf1 100644
--- a/obp-commons/pom.xml
+++ b/obp-commons/pom.xml
@@ -29,6 +29,16 @@
net.liftweb
lift-util_${scala.version}
+
+
+ javax.activation
+ activation
+
+
+ javax.mail
+ mail
+
+
net.liftweb