SendGridService.kt
package delta.codecharacter.server.sendgrid
import com.sendgrid.Method
import com.sendgrid.Request
import com.sendgrid.Response
import com.sendgrid.SendGrid
import com.sendgrid.helpers.mail.Mail
import com.sendgrid.helpers.mail.objects.Content
import com.sendgrid.helpers.mail.objects.Email
import delta.codecharacter.server.exception.CustomException
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.http.HttpStatus
import org.springframework.stereotype.Service
import java.util.UUID
@Service
class SendGridService {
private val logger: Logger = LoggerFactory.getLogger(SendGridService::class.java)
@Autowired private lateinit var sendGrid: SendGrid
@Value("\${spring.sendgrid.sender-email}") private lateinit var senderEmail: String
// @Value("\${spring.sendgrid.template-id}") private lateinit var templateId: String
@Value("\${base-url}") private lateinit var baseUrl: String
fun activateUserEmail(userId: UUID, token: String, name: String, email: String) {
val link = "$baseUrl#/activate?id=$userId&token=$token"
val linkName = "User Activation"
val message = "You are just one step away from activating your CodeCharacter account"
val disregardMessage = "If you did not create an account with us,please disregard this email"
val buttonName = "Activate"
val subjectInfo = "CodeCharacter Account Activation Link"
sendTemplateEmail(
email, name, linkName, link, message, disregardMessage, buttonName, subjectInfo
)
}
fun resetPasswordEmail(userId: UUID, token: String, name: String, email: String) {
val link = "$baseUrl#/reset-password?id=$userId&token=$token"
val linkName = "Reset-Password link"
val message = "Please click the button to reset your password"
val disregardMessage = "If you did not request a password reset,please ignore this email."
val buttonName = "Reset Password"
val subjectInfo = "CodeCharacter Reset-Password Link"
sendTemplateEmail(
email, name, linkName, link, message, disregardMessage, buttonName, subjectInfo
)
}
fun sendTemplateEmail(
emailTo: String,
name: String,
linkName: String,
link: String,
message: String,
disregardMessage: String,
buttonName: String,
subjectInfo: String
) {
// Using DynamicTemplates are preferred but we dont have creds to access that so we used this :(
// val mail = Mail()
// val personalization = DynamicTemplatePersonalization()
// personalization.addTo(Email(emailTo))
// mail.setFrom(Email(senderEmail))
// mail.setSubject(subjectInfo)
// personalization.addDynamicTemplateData("name", name)
// personalization.addDynamicTemplateData("link_name", linkName)
// personalization.addDynamicTemplateData("message", message)
// personalization.addDynamicTemplateData("link", link)
// personalization.addDynamicTemplateData("button_name", buttonName)
// personalization.addDynamicTemplateData("subject", subjectInfo)
// mail.addPersonalization(personalization)
// mail.setTemplateId(templateId)
val emailContent =
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" +
"<html data-editor-version=\"2\" class=\"sg-campaigns\" xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
" <head>\n" +
" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n" +
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1\">\n" +
" <!--[if !mso]><!-->\n" +
" <meta http-equiv=\"X-UA-Compatible\" content=\"IE=Edge\">\n" +
" <!--<![endif]-->\n" +
" <!--[if (gte mso 9)|(IE)]>\n" +
" <xml>\n" +
" <o:OfficeDocumentSettings>\n" +
" <o:AllowPNG/>\n" +
" <o:PixelsPerInch>96</o:PixelsPerInch>\n" +
" </o:OfficeDocumentSettings>\n" +
" </xml>\n" +
" <![endif]-->\n" +
" <!--[if (gte mso 9)|(IE)]>\n" +
" <style type=\"text/css\">\n" +
" body {width: 620px;margin: 0 auto;}\n" +
" table {border-collapse: collapse;}\n" +
" table, td {mso-table-lspace: 0pt;mso-table-rspace: 0pt;}\n" +
" img {-ms-interpolation-mode: bicubic;}\n" +
" </style>\n" +
"<![endif]-->\n" +
" <style type=\"text/css\">\n" +
" body, p, div {\n" +
" font-family: arial,helvetica,sans-serif;\n" +
" font-size: 14px;\n" +
" }\n" +
" body {\n" +
" color: #000000;\n" +
" }\n" +
" body a {\n" +
" color: #932A89;\n" +
" text-decoration: none;\n" +
" }\n" +
" p { margin: 0; padding: 0; }\n" +
" table.wrapper {\n" +
" width:100% !important;\n" +
" table-layout: fixed;\n" +
" -webkit-font-smoothing: antialiased;\n" +
" -webkit-text-size-adjust: 100%;\n" +
" -moz-text-size-adjust: 100%;\n" +
" -ms-text-size-adjust: 100%;\n" +
" }\n" +
" img.max-width {\n" +
" max-width: 100% !important;\n" +
" }\n" +
" .column.of-2 {\n" +
" width: 50%;\n" +
" }\n" +
" .column.of-3 {\n" +
" width: 33.333%;\n" +
" }\n" +
" .column.of-4 {\n" +
" width: 25%;\n" +
" }\n" +
" ul ul ul ul {\n" +
" list-style-type: disc !important;\n" +
" }\n" +
" ol ol {\n" +
" list-style-type: lower-roman !important;\n" +
" }\n" +
" ol ol ol {\n" +
" list-style-type: lower-latin !important;\n" +
" }\n" +
" ol ol ol ol {\n" +
" list-style-type: decimal !important;\n" +
" }\n" +
" @media screen and (max-width:480px) {\n" +
" .preheader .rightColumnContent,\n" +
" .footer .rightColumnContent {\n" +
" text-align: left !important;\n" +
" }\n" +
" .preheader .rightColumnContent div,\n" +
" .preheader .rightColumnContent span,\n" +
" .footer .rightColumnContent div,\n" +
" .footer .rightColumnContent span {\n" +
" text-align: left !important;\n" +
" }\n" +
" .preheader .rightColumnContent,\n" +
" .preheader .leftColumnContent {\n" +
" font-size: 80% !important;\n" +
" padding: 5px 0;\n" +
" }\n" +
" table.wrapper-mobile {\n" +
" width: 100% !important;\n" +
" table-layout: fixed;\n" +
" }\n" +
" img.max-width {\n" +
" height: auto !important;\n" +
" max-width: 100% !important;\n" +
" }\n" +
" a.bulletproof-button {\n" +
" display: block !important;\n" +
" width: auto !important;\n" +
" font-size: 80%;\n" +
" padding-left: 0 !important;\n" +
" padding-right: 0 !important;\n" +
" }\n" +
" .columns {\n" +
" width: 100% !important;\n" +
" }\n" +
" .column {\n" +
" display: block !important;\n" +
" width: 100% !important;\n" +
" padding-left: 0 !important;\n" +
" padding-right: 0 !important;\n" +
" margin-left: 0 !important;\n" +
" margin-right: 0 !important;\n" +
" }\n" +
" .social-icon-column {\n" +
" display: inline-block !important;\n" +
" }\n" +
" }\n" +
" </style>\n" +
" <style>\n" +
" @media screen and (max-width:480px) {\n" +
" table\\0 {\n" +
" width: 480px !important;\n" +
" }\n" +
" }\n" +
" </style>\n" +
" <!--user entered Head Start--><!--End Head user entered-->\n" +
" </head>\n" +
" <body>\n" +
" <center class=\"wrapper\" data-link-color=\"#932A89\" data-body-style=\"font-size:14px; font-family:arial,helvetica,sans-serif; color:#000000; background-color:#f0f0f0;\">\n" +
" <div class=\"webkit\">\n" +
" <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" class=\"wrapper\" bgcolor=\"#f0f0f0\">\n" +
" <tr>\n" +
" <td valign=\"top\" bgcolor=\"#f0f0f0\" width=\"100%\">\n" +
" <table width=\"100%\" role=\"content-container\" class=\"outer\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n" +
" <tr>\n" +
" <td width=\"100%\">\n" +
" <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n" +
" <tr>\n" +
" <td>\n" +
" <!--[if mso]>\n" +
" <center>\n" +
" <table><tr><td width=\"620\">\n" +
" <![endif]-->\n" +
" <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"width:100%; max-width:620px;\" align=\"center\">\n" +
" <tr>\n" +
" <td role=\"modules-container\" style=\"padding:0px 10px 0px 10px; color:#000000; text-align:left;\" bgcolor=\"#F0F0F0\" width=\"100%\" align=\"left\"><table class=\"module preheader preheader-hide\" role=\"module\" data-type=\"preheader\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"display: none !important; mso-hide: all; visibility: hidden; opacity: 0; color: transparent; height: 0; width: 0;\">\n" +
" <tr>\n" +
" <td role=\"module-content\">\n" +
" <p></p>\n" +
" </td>\n" +
" </tr>\n" +
" </table><table class=\"module\" role=\"module\" data-type=\"text\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"table-layout: fixed;\" data-muid=\"806c535f-a48e-47c3-84e1-e42f460fcd8b\" data-mc-module-version=\"2019-10-22\">\n" +
" <tbody>\n" +
" <tr>\n" +
" <td style=\"padding:5px 0px 5px 120px; line-height:12px; text-align:inherit; background-color:#f0f0f0;\" height=\"100%\" valign=\"top\" bgcolor=\"#f0f0f0\" role=\"module-content\"><div><div style=\"font-family: inherit; text-align: right\"><span style=\"font-family: "trebuchet ms", helvetica, sans-serif; color: #9d9d9d; font-size: 10px\">Email not displaying correctly? </span><span style=\"font-family: "trebuchet ms", helvetica, sans-serif; color: #932a89; font-size: 10px\"><strong>VIEW IT</strong></span><span style=\"font-family: "trebuchet ms", helvetica, sans-serif; color: #9d9d9d; font-size: 10px\"> in your browser.</span></div><div></div></div></td>\n" +
" </tr>\n" +
" </tbody>\n" +
" </table><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" align=\"center\" width=\"100%\" role=\"module\" data-type=\"columns\" style=\"padding:50px 20px 50px 20px;\" bgcolor=\"#1a1a1a\" data-distribution=\"1\">\n" +
" <tbody>\n" +
" <tr role=\"module-content\">\n" +
" <td height=\"100%\" valign=\"top\"><table width=\"460\" style=\"width:460px; border-spacing:0; border-collapse:collapse; margin:0px 50px 0px 50px;\" cellpadding=\"0\" cellspacing=\"0\" align=\"left\" border=\"0\" bgcolor=\"\" class=\"column column-0\">\n" +
" <tbody>\n" +
" <tr>\n" +
" <td style=\"padding:0px;margin:0px;border-spacing:0;\"><table class=\"module\" role=\"module\" data-type=\"text\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"table-layout: fixed;\" data-muid=\"efe5a2c4-1b11-49e7-889d-856d80b40f63\" data-mc-module-version=\"2019-10-22\">\n" +
" <tbody>\n" +
" <tr>\n" +
" <td style=\"padding:40px 0px 30px 0px; line-height:36px; text-align:inherit; background-color:#5e5959;\" height=\"100%\" valign=\"top\" bgcolor=\"#5e5959\" role=\"module-content\"><div><div style=\"font-family: inherit; text-align: center\"><span style=\"font-size: 36px\">$linkName</span></div><div></div></div></td>\n" +
" </tr>\n" +
" </tbody>\n" +
" </table><table class=\"module\" role=\"module\" data-type=\"text\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"table-layout: fixed;\" data-muid=\"efe5a2c4-1b11-49e7-889d-856d80b40f63.2\" data-mc-module-version=\"2019-10-22\">\n" +
" <tbody>\n" +
" <tr>\n" +
" <td style=\"padding:50px 30px 30px 30px; line-height:28px; text-align:inherit; background-color:#ffffff;\" height=\"100%\" valign=\"top\" bgcolor=\"#ffffff\" role=\"module-content\"><div><div style=\"font-family: inherit; text-align: inherit\"><span style=\"font-size: 20px; font-family: "trebuchet ms", helvetica, sans-serif; color: #656565\">Hi $name,</span></div>\n" +
"<div style=\"font-family: inherit; text-align: inherit\"><br></div>\n" +
"<div style=\"font-family: inherit; text-align: inherit\"><span style=\"font-size: 20px; font-family: "trebuchet ms", helvetica, sans-serif; color: #656565\">$message,</span></div>\n" +
"<div style=\"font-family: inherit; text-align: inherit\"><br></div>\n" +
"<div style=\"font-family: inherit; text-align: inherit\"><span style=\"font-size: 20px; font-family: "trebuchet ms", helvetica, sans-serif; color: #656565\">$disregardMessage</span></div><div></div></div></td>\n" +
" </tr>\n" +
" </tbody>\n" +
" </table><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"module\" data-role=\"module-button\" data-type=\"button\" role=\"module\" style=\"table-layout:fixed;\" width=\"100%\" data-muid=\"7e9e5ded-d560-42a6-8e95-14ac7fdc0977\">\n" +
" <tbody>\n" +
" <tr>\n" +
" <td align=\"center\" bgcolor=\"#ffffff\" class=\"outer-td\" style=\"padding:0px 0px 0px 0px; background-color:#ffffff;\">\n" +
" <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"wrapper-mobile\" style=\"text-align:center;\">\n" +
" <tbody>\n" +
" <tr>\n" +
" <td align=\"center\" bgcolor=\"#333333\" class=\"inner-td\" style=\"border-radius:6px; font-size:16px; text-align:center; background-color:inherit;\">\n" +
" <a href=\"${link}\" style=\"background-color:#333333; border:1px solid #000000; border-color:#000000; border-radius:6px; border-width:1px; color:#ffffff; display:inline-block; font-size:14px; font-weight:normal; letter-spacing:0px; line-height:normal; padding:12px 18px 12px 18px; text-align:center; text-decoration:none; border-style:solid; font-family:arial black, helvetica, sans-serif;\" target=\"_blank\">$buttonName</a>\n" +
" </td>\n" +
" </tr>\n" +
" </tbody>\n" +
" </table>\n" +
" </td>\n" +
" </tr>\n" +
" </tbody>\n" +
" </table><table class=\"module\" role=\"module\" data-type=\"text\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"table-layout: fixed;\" data-muid=\"efe5a2c4-1b11-49e7-889d-856d80b40f63.1\" data-mc-module-version=\"2019-10-22\">\n" +
" <tbody>\n" +
" <tr>\n" +
" <td style=\"padding:40px 100px 50px 30px; line-height:26px; text-align:inherit; background-color:#FFFFFF;\" height=\"100%\" valign=\"top\" bgcolor=\"#FFFFFF\" role=\"module-content\"><div><div style=\"font-family: inherit; text-align: inherit\"><span style=\"font-family: "trebuchet ms", helvetica, sans-serif; font-size: 16px; color: #656565\">With Regards!</span></div>\n" +
"<div style=\"font-family: inherit; text-align: inherit\"><span style=\"font-family: "trebuchet ms", helvetica, sans-serif; font-size: 16px; color: #656565\">CodeCharacter</span></div><div></div></div></td>\n" +
" </tr>\n" +
" </tbody>\n" +
" </table></td>\n" +
" </tr>\n" +
" </tbody>\n" +
" </table></td>\n" +
" </tr>\n" +
" </tbody>\n" +
" </table><table class=\"module\" role=\"module\" data-type=\"text\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"table-layout: fixed;\" data-muid=\"13d36c46-b515-4bdf-ad3c-edafb5c1c151.1.1\" data-mc-module-version=\"2019-10-22\">\n" +
" <tbody>\n" +
" <tr>\n" +
" <td style=\"padding:0px 0px 25px 0px; line-height:32px; text-align:inherit; background-color:#000000;\" height=\"100%\" valign=\"top\" bgcolor=\"#000000\" role=\"module-content\"><div><div style=\"font-family: inherit; text-align: center\"><span style=\"font-family: "trebuchet ms", helvetica, sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: center; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline; font-size: 16px; color: #ffffff\">CodeCharatcer-2023</span></div><div></div></div></td>\n" +
" </tr>\n" +
" </tbody>\n" +
" </table></td>\n" +
" </tr>\n" +
" </table>\n" +
" <!--[if mso]>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </center>\n" +
" <![endif]-->\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </div>\n" +
" </center>\n" +
" </body>\n" +
" </html>"
val content = Content("text/html", emailContent)
val mail = Mail(Email(senderEmail), subjectInfo, Email(emailTo), content)
val request = Request()
try {
request.apply {
method = Method.POST
endpoint = "mail/send"
body = mail.build()
}
val response: Response = sendGrid.api(request)
if (response.statusCode >= 400) {
logger.error(
"Error while sending email with status: ${response.statusCode}. Error: ${response.body}"
)
throw CustomException(
HttpStatus.INTERNAL_SERVER_ERROR, "Unknown error. Please contact event admins."
)
}
} catch (e: Exception) {
logger.error("Error while sending email: ${e.message}")
throw CustomException(
HttpStatus.INTERNAL_SERVER_ERROR, "Unknown error. Please contact event admins."
)
}
}
}