-
-
Notifications
You must be signed in to change notification settings - Fork 304
feat: React Emails > default template #3194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: cynthia/react-email
Are you sure you want to change the base?
Changes from all commits
cdb4f02
f95c57e
dcb6fb1
95165cb
3042fea
2684cd3
d229261
5c23cab
d6fb732
b75ec69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,69 +1,28 @@ | ||
package io.tolgee.component.email | ||
|
||
import io.tolgee.configuration.tolgee.TolgeeProperties | ||
import io.tolgee.dtos.misc.EmailParams | ||
import org.springframework.core.io.ClassPathResource | ||
import org.springframework.mail.javamail.JavaMailSender | ||
import io.tolgee.email.EmailService | ||
import org.springframework.stereotype.Component | ||
import java.util.Locale | ||
|
||
@Component | ||
class TolgeeEmailSender( | ||
private val tolgeeProperties: TolgeeProperties, | ||
private val mailSender: JavaMailSender, | ||
private val mimeMessageHelperFactory: MimeMessageHelperFactory, | ||
private val emailService: EmailService, | ||
) { | ||
fun sendEmail(params: EmailParams) { | ||
validateProps() | ||
val helper = mimeMessageHelperFactory.create() | ||
helper.setFrom(params.from ?: tolgeeProperties.smtp.from!!) | ||
helper.setTo(params.to) | ||
params.replyTo?.let { | ||
helper.setReplyTo(it) | ||
} | ||
if (!params.bcc.isNullOrEmpty()) { | ||
helper.setBcc(params.bcc!!) | ||
} | ||
helper.setSubject(params.subject) | ||
val content = | ||
""" | ||
<html> | ||
<body style="font-size: 15px"> | ||
${params.text}<br/><br/> | ||
<img style="max-width: 100%; width:120px" src="cid:logo.png" /> | ||
</body> | ||
</html> | ||
""".trimIndent() | ||
helper.setText(content, true) | ||
|
||
params.attachments.forEach { | ||
helper.addAttachment(it.name, it.inputStreamSource) | ||
} | ||
|
||
helper.addInline( | ||
"logo.png", | ||
{ ClassPathResource("tolgee-logo.png").inputStream }, | ||
"image/png", | ||
val properties = mapOf<String, Any>() | ||
.let { if (params.text != null) it.plus("content" to params.text!!) else it } | ||
.let { if (params.header != null) it.plus("header" to params.header!!) else it } | ||
.let { if (params.recipientName != null) it.plus("recipientName" to params.recipientName!!) else it } | ||
emailService.sendEmailTemplate( | ||
recipient = params.to, | ||
subject = params.subject, | ||
template = params.templateName ?: "default", | ||
locale = Locale.ENGLISH, | ||
properties = properties, | ||
attachments = params.attachments, | ||
bcc = params.bcc, | ||
replyTo = params.replyTo, | ||
) | ||
|
||
mailSender.send(helper.mimeMessage) | ||
} | ||
|
||
private fun validateProps() { | ||
if (tolgeeProperties.smtp.from.isNullOrEmpty()) { | ||
throw IllegalStateException( | ||
"""tolgee.smtp.from property not provided. | ||
|You have to configure smtp properties to send an e-mail. | ||
""".trimMargin(), | ||
) | ||
} | ||
} | ||
|
||
fun getSignature(): String { | ||
return """ | ||
<br /><br /> | ||
Best regards, | ||
<br /> | ||
Tolgee Team | ||
""".trimIndent() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ | |
|
||
package io.tolgee.email | ||
|
||
import io.tolgee.component.FrontendUrlProvider | ||
import io.tolgee.component.publicBillingConfProvider.PublicBillingConfProvider | ||
import io.tolgee.configuration.tolgee.TolgeeProperties | ||
import org.springframework.stereotype.Component | ||
|
@@ -27,14 +28,16 @@ class EmailGlobalVariablesProvider( | |
// Used to identify whether we're Tolgee Cloud or not | ||
private val billingConfigProvider: PublicBillingConfProvider, | ||
private val tolgeeProperties: TolgeeProperties, | ||
private val frontendUrlProvider: FrontendUrlProvider, | ||
) { | ||
operator fun invoke(): Map<String, Any?> { | ||
val isCloud = billingConfigProvider().enabled | ||
val backendUrl = tolgeeProperties.backEndUrl ?: frontendUrlProvider.url | ||
|
||
return mapOf( | ||
"isCloud" to isCloud, | ||
"instanceQualifier" to if (isCloud) tolgeeProperties.appName else tolgeeProperties.frontEndUrl.intoQualifier(), | ||
"instanceUrl" to tolgeeProperties.frontEndUrl, | ||
"instanceQualifier" to if (isCloud) tolgeeProperties.appName else backendUrl.intoQualifier(), | ||
"backendUrl" to backendUrl | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unsure about that... Especially wrt the instance qualifier. The fallback to using the domain name people are using to access Tolgee is likely a lot more recognizable than whatever internal URL is used. Problems in development environment are likely related to the fact I completely overlooked that and didn't add the appropriate proxy config to Vite 😅 |
||
) | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,7 @@ | |
|
||
package io.tolgee.email | ||
|
||
import io.tolgee.configuration.tolgee.SmtpProperties | ||
import io.tolgee.configuration.tolgee.TolgeeProperties | ||
import io.tolgee.dtos.misc.EmailAttachment | ||
import org.springframework.beans.factory.annotation.Qualifier | ||
import org.springframework.context.ApplicationContext | ||
|
@@ -32,14 +32,14 @@ import java.util.* | |
@Service | ||
class EmailService( | ||
private val applicationContext: ApplicationContext, | ||
private val smtpProperties: SmtpProperties, | ||
private val tolgeeProperties: TolgeeProperties, | ||
private val mailSender: JavaMailSender, | ||
private val emailGlobalVariablesProvider: EmailGlobalVariablesProvider, | ||
@Qualifier("emailTemplateEngine") private val templateEngine: TemplateEngine, | ||
) { | ||
private val smtpFrom | ||
get() = | ||
smtpProperties.from | ||
tolgeeProperties.smtp.from | ||
?: throw IllegalStateException( | ||
"SMTP sender is not configured. " + | ||
"See https://docs.tolgee.io/platform/self_hosting/configuration#smtp", | ||
|
@@ -52,6 +52,9 @@ class EmailService( | |
locale: Locale, | ||
properties: Map<String, Any> = mapOf(), | ||
attachments: List<EmailAttachment> = listOf(), | ||
subject: String? = null, | ||
bcc: Array<String>? = null, | ||
replyTo: String? = null, | ||
) { | ||
val globalVariables = emailGlobalVariablesProvider() | ||
val context = Context(locale, properties) | ||
|
@@ -63,8 +66,8 @@ class EmailService( | |
context.setVariable(ThymeleafEvaluationContext.THYMELEAF_EVALUATION_CONTEXT_CONTEXT_VARIABLE_NAME, tec) | ||
|
||
val html = templateEngine.process(template, context) | ||
val subject = extractEmailTitle(html) | ||
sendEmail(recipient, subject, html, attachments) | ||
val subject = subject ?: extractEmailTitle(html) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: Setting a subject would break internationalization of emails. I guess this is needed for the backcompat layer, but... not ideal as it makes the service contract loose here :( I don't think the template allows the subject being a variable directly but that could be mitigated with a passthrough i18n string; i.e. |
||
sendEmail(recipient, subject, html, attachments, bcc, replyTo) | ||
} | ||
|
||
@Async | ||
|
@@ -73,6 +76,8 @@ class EmailService( | |
subject: String, | ||
contents: String, | ||
attachments: List<EmailAttachment> = listOf(), | ||
bcc: Array<String>? = null, | ||
replyTo: String? = null, | ||
) { | ||
val message = mailSender.createMimeMessage() | ||
val helper = MimeMessageHelper(message, MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED, "UTF8") | ||
|
@@ -81,6 +86,12 @@ class EmailService( | |
helper.setTo(recipient) | ||
helper.setSubject(subject) | ||
helper.setText(contents, true) | ||
if (!bcc.isNullOrEmpty()) { | ||
helper.setBcc(bcc) | ||
} | ||
replyTo?.let { | ||
helper.setReplyTo(it) | ||
} | ||
attachments.forEach { helper.addAttachment(it.name, it.inputStreamSource) } | ||
|
||
mailSender.send(message) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, I recon my original idea was to eventually deprecate that component; i.e. new code would use the new email system while legacy code can still use this until it is eventually migrated to use a dedicated template. Not sure templateName is needed 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We agreed to wrap all existing emails in a default template and just drop the legacy email text into it. Since the new email designs aren’t ready yet, this lets us still use the feature in the meantime 😀