fix: move email styles to <style> block and remove watermark image
Extracts repeated inline styles into <head> <style> to improve the text-to-HTML ratio flagged by mail checkers. Removes the decorative watermark <img> (opacity 0.07, barely visible) which was the only image element and triggered the "too many images" classification. Cleans up the now-unused ProvisioningProperties dependency from EmailConnectorService and PasswordResetNotificationService. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
package net.siegeln.cameleer.saas.notification;
|
package net.siegeln.cameleer.saas.notification;
|
||||||
|
|
||||||
import net.siegeln.cameleer.saas.identity.LogtoManagementClient;
|
import net.siegeln.cameleer.saas.identity.LogtoManagementClient;
|
||||||
import net.siegeln.cameleer.saas.provisioning.ProvisioningProperties;
|
|
||||||
import net.siegeln.cameleer.saas.vendor.EmailConnectorService;
|
import net.siegeln.cameleer.saas.vendor.EmailConnectorService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -28,14 +27,11 @@ public class PasswordResetNotificationService {
|
|||||||
|
|
||||||
private final EmailConnectorService emailConnectorService;
|
private final EmailConnectorService emailConnectorService;
|
||||||
private final LogtoManagementClient logtoClient;
|
private final LogtoManagementClient logtoClient;
|
||||||
private final ProvisioningProperties provisioningProps;
|
|
||||||
|
|
||||||
public PasswordResetNotificationService(EmailConnectorService emailConnectorService,
|
public PasswordResetNotificationService(EmailConnectorService emailConnectorService,
|
||||||
LogtoManagementClient logtoClient,
|
LogtoManagementClient logtoClient) {
|
||||||
ProvisioningProperties provisioningProps) {
|
|
||||||
this.emailConnectorService = emailConnectorService;
|
this.emailConnectorService = emailConnectorService;
|
||||||
this.logtoClient = logtoClient;
|
this.logtoClient = logtoClient;
|
||||||
this.provisioningProps = provisioningProps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,12 +110,8 @@ public class PasswordResetNotificationService {
|
|||||||
String content = new ClassPathResource("email-templates/password-reset-notification.html")
|
String content = new ClassPathResource("email-templates/password-reset-notification.html")
|
||||||
.getContentAsString(StandardCharsets.UTF_8);
|
.getContentAsString(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
String watermarkUrl = provisioningProps.publicProtocol() + "://"
|
|
||||||
+ provisioningProps.publicHost() + "/platform/assets/email-watermark.png";
|
|
||||||
String timestamp = ZonedDateTime.now(ZoneOffset.UTC).format(TIMESTAMP_FMT);
|
String timestamp = ZonedDateTime.now(ZoneOffset.UTC).format(TIMESTAMP_FMT);
|
||||||
|
|
||||||
return content
|
return content.replace("{{timestamp}}", timestamp);
|
||||||
.replace("{{watermarkUrl}}", watermarkUrl)
|
|
||||||
.replace("{{timestamp}}", timestamp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package net.siegeln.cameleer.saas.vendor;
|
package net.siegeln.cameleer.saas.vendor;
|
||||||
|
|
||||||
import net.siegeln.cameleer.saas.identity.LogtoManagementClient;
|
import net.siegeln.cameleer.saas.identity.LogtoManagementClient;
|
||||||
import net.siegeln.cameleer.saas.provisioning.ProvisioningProperties;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
@@ -20,11 +19,9 @@ public class EmailConnectorService {
|
|||||||
private static final String SMTP_FACTORY_ID = "simple-mail-transfer-protocol";
|
private static final String SMTP_FACTORY_ID = "simple-mail-transfer-protocol";
|
||||||
|
|
||||||
private final LogtoManagementClient logtoClient;
|
private final LogtoManagementClient logtoClient;
|
||||||
private final ProvisioningProperties provisioningProps;
|
|
||||||
|
|
||||||
public EmailConnectorService(LogtoManagementClient logtoClient, ProvisioningProperties provisioningProps) {
|
public EmailConnectorService(LogtoManagementClient logtoClient) {
|
||||||
this.logtoClient = logtoClient;
|
this.logtoClient = logtoClient;
|
||||||
this.provisioningProps = provisioningProps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public record SmtpConfig(String host, int port, String username, String password, String fromEmail) {}
|
public record SmtpConfig(String host, int port, String username, String password, String fromEmail) {}
|
||||||
@@ -160,14 +157,11 @@ public class EmailConnectorService {
|
|||||||
return "SignInAndRegister".equals(signInExp.get("signInMode"));
|
return "SignInAndRegister".equals(signInExp.get("signInMode"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Load an email template from classpath and resolve the watermark URL placeholder. */
|
/** Load an email template from classpath. */
|
||||||
private String loadTemplate(String filename) {
|
private String loadTemplate(String filename) {
|
||||||
try {
|
try {
|
||||||
String content = new ClassPathResource("email-templates/" + filename)
|
return new ClassPathResource("email-templates/" + filename)
|
||||||
.getContentAsString(StandardCharsets.UTF_8);
|
.getContentAsString(StandardCharsets.UTF_8);
|
||||||
String watermarkUrl = provisioningProps.publicProtocol() + "://"
|
|
||||||
+ provisioningProps.publicHost() + "/platform/assets/email-watermark.png";
|
|
||||||
return content.replace("{{watermarkUrl}}", watermarkUrl);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalStateException("Failed to load email template: " + filename, e);
|
throw new IllegalStateException("Failed to load email template: " + filename, e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,32 +5,45 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<title>Reset your Cameleer password</title>
|
<title>Reset your Cameleer password</title>
|
||||||
|
<style>
|
||||||
|
body { margin:0; padding:0; background:#f5f1eb; }
|
||||||
|
.wrapper { font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; max-width:480px; margin:0 auto; background:#fff; border-radius:8px; overflow:hidden; border:1px solid #e8e0d4; }
|
||||||
|
.header { background:#C6820E; padding:20px 24px; text-align:center; }
|
||||||
|
.header span { font-size:22px; font-weight:700; color:#fff; letter-spacing:0.5px; }
|
||||||
|
.content { padding:32px 24px 24px; }
|
||||||
|
.title { color:#1a1a1a; font-size:16px; font-weight:600; margin:0 0 8px; }
|
||||||
|
.subtitle { color:#444; font-size:14px; line-height:1.6; margin:0 0 24px; }
|
||||||
|
.code-box { text-align:center; margin:0 0 24px; }
|
||||||
|
.code-box div { display:inline-block; background:#FDF6EC; border:2px solid #C6820E; border-radius:8px; padding:16px 32px; }
|
||||||
|
.code-box span { font-size:32px; font-weight:700; letter-spacing:8px; color:#C6820E; font-family:'Courier New',Courier,monospace; }
|
||||||
|
.hint { color:#888; font-size:13px; line-height:1.5; margin:0 0 16px; }
|
||||||
|
.detail { color:#888; font-size:13px; line-height:1.5; margin:0; }
|
||||||
|
.footer { border-top:1px solid #e8e0d4; padding:16px 24px; text-align:center; }
|
||||||
|
.footer p { margin:0; }
|
||||||
|
.footer .contact { color:#999; font-size:12px; }
|
||||||
|
.footer .tagline { color:#bbb; font-size:11px; margin-top:6px; }
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body style="margin:0;padding:0;background:#f5f1eb;">
|
<body>
|
||||||
<!--[if mso]><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center"><![endif]-->
|
<div class="wrapper">
|
||||||
<div style="font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;max-width:480px;margin:0 auto;background:#ffffff;border-radius:8px;overflow:hidden;border:1px solid #e8e0d4;">
|
<div class="header">
|
||||||
<div style="background:#C6820E;padding:20px 24px;text-align:center;">
|
<span>Cameleer.io</span>
|
||||||
<span style="font-size:22px;font-weight:700;color:#ffffff;letter-spacing:0.5px;">Cameleer.io</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:32px 24px 24px;position:relative;overflow:hidden;">
|
<div class="content">
|
||||||
<img src="{{watermarkUrl}}" style="position:absolute;top:-30px;right:-50px;width:320px;height:320px;opacity:0.07;pointer-events:none;border:0;outline:none;" alt="" />
|
<p class="title">Lost in the dunes?</p>
|
||||||
<div style="position:relative;">
|
<p class="subtitle">No worries — enter this code to reset your password and get back on the trail.</p>
|
||||||
<p style="color:#1a1a1a;font-size:16px;font-weight:600;margin:0 0 8px;">Lost in the dunes?</p>
|
<div class="code-box">
|
||||||
<p style="color:#444;font-size:14px;line-height:1.6;margin:0 0 24px;">No worries — enter this code to reset your password and get back on the trail.</p>
|
<div>
|
||||||
<div style="text-align:center;margin:0 0 24px;">
|
<span>{{code}}</span>
|
||||||
<div style="display:inline-block;background:#FDF6EC;border:2px solid #C6820E;border-radius:8px;padding:16px 32px;">
|
|
||||||
<span style="font-size:32px;font-weight:700;letter-spacing:8px;color:#C6820E;font-family:'Courier New',Courier,monospace;">{{code}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<p style="color:#888;font-size:13px;line-height:1.5;margin:0 0 16px;">This code expires in 10 minutes. If you didn't request a password reset, you can safely ignore this email.</p>
|
|
||||||
<p style="color:#888;font-size:13px;line-height:1.5;margin:0;">This password reset was requested for your Cameleer account. Cameleer is an observability platform for Apache Camel integrations providing real-time route tracing, message inspection, and performance monitoring. For security, this code can only be used once. If you continue to have trouble accessing your account, please contact your administrator for assistance.</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="hint">This code expires in 10 minutes. If you didn't request a password reset, you can safely ignore this email.</p>
|
||||||
|
<p class="detail">This password reset was requested for your Cameleer account. Cameleer is an observability platform for Apache Camel integrations providing real-time route tracing, message inspection, and performance monitoring. For security, this code can only be used once. If you continue to have trouble accessing your account, please contact your administrator for assistance.</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="border-top:1px solid #e8e0d4;padding:16px 24px;text-align:center;">
|
<div class="footer">
|
||||||
<p style="color:#999;font-size:12px;margin:0;">Questions? Contact your administrator</p>
|
<p class="contact">Questions? Contact your administrator</p>
|
||||||
<p style="color:#bbb;font-size:11px;margin:6px 0 0;">Cameleer — Apache Camel observability</p>
|
<p class="tagline">Cameleer — Apache Camel observability</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--[if mso]></td></tr></table><![endif]-->
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -5,32 +5,45 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<title>Your Cameleer verification code</title>
|
<title>Your Cameleer verification code</title>
|
||||||
|
<style>
|
||||||
|
body { margin:0; padding:0; background:#f5f1eb; }
|
||||||
|
.wrapper { font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; max-width:480px; margin:0 auto; background:#fff; border-radius:8px; overflow:hidden; border:1px solid #e8e0d4; }
|
||||||
|
.header { background:#C6820E; padding:20px 24px; text-align:center; }
|
||||||
|
.header span { font-size:22px; font-weight:700; color:#fff; letter-spacing:0.5px; }
|
||||||
|
.content { padding:32px 24px 24px; }
|
||||||
|
.title { color:#1a1a1a; font-size:16px; font-weight:600; margin:0 0 8px; }
|
||||||
|
.subtitle { color:#444; font-size:14px; line-height:1.6; margin:0 0 24px; }
|
||||||
|
.code-box { text-align:center; margin:0 0 24px; }
|
||||||
|
.code-box div { display:inline-block; background:#FDF6EC; border:2px solid #C6820E; border-radius:8px; padding:16px 32px; }
|
||||||
|
.code-box span { font-size:32px; font-weight:700; letter-spacing:8px; color:#C6820E; font-family:'Courier New',Courier,monospace; }
|
||||||
|
.hint { color:#888; font-size:13px; line-height:1.5; margin:0 0 16px; }
|
||||||
|
.detail { color:#888; font-size:13px; line-height:1.5; margin:0; }
|
||||||
|
.footer { border-top:1px solid #e8e0d4; padding:16px 24px; text-align:center; }
|
||||||
|
.footer p { margin:0; }
|
||||||
|
.footer .contact { color:#999; font-size:12px; }
|
||||||
|
.footer .tagline { color:#bbb; font-size:11px; margin-top:6px; }
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body style="margin:0;padding:0;background:#f5f1eb;">
|
<body>
|
||||||
<!--[if mso]><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center"><![endif]-->
|
<div class="wrapper">
|
||||||
<div style="font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;max-width:480px;margin:0 auto;background:#ffffff;border-radius:8px;overflow:hidden;border:1px solid #e8e0d4;">
|
<div class="header">
|
||||||
<div style="background:#C6820E;padding:20px 24px;text-align:center;">
|
<span>Cameleer.io</span>
|
||||||
<span style="font-size:22px;font-weight:700;color:#ffffff;letter-spacing:0.5px;">Cameleer.io</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:32px 24px 24px;position:relative;overflow:hidden;">
|
<div class="content">
|
||||||
<img src="{{watermarkUrl}}" style="position:absolute;top:-30px;right:-50px;width:320px;height:320px;opacity:0.07;pointer-events:none;border:0;outline:none;" alt="" />
|
<p class="title">Quick checkpoint</p>
|
||||||
<div style="position:relative;">
|
<p class="subtitle">Here's your verification code. Just making sure it's really you at the reins.</p>
|
||||||
<p style="color:#1a1a1a;font-size:16px;font-weight:600;margin:0 0 8px;">Quick checkpoint</p>
|
<div class="code-box">
|
||||||
<p style="color:#444;font-size:14px;line-height:1.6;margin:0 0 24px;">Here's your verification code. Just making sure it's really you at the reins.</p>
|
<div>
|
||||||
<div style="text-align:center;margin:0 0 24px;">
|
<span>{{code}}</span>
|
||||||
<div style="display:inline-block;background:#FDF6EC;border:2px solid #C6820E;border-radius:8px;padding:16px 32px;">
|
|
||||||
<span style="font-size:32px;font-weight:700;letter-spacing:8px;color:#C6820E;font-family:'Courier New',Courier,monospace;">{{code}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<p style="color:#888;font-size:13px;line-height:1.5;margin:0 0 16px;">This code expires in 10 minutes.</p>
|
|
||||||
<p style="color:#888;font-size:13px;line-height:1.5;margin:0;">You are receiving this email because a verification was requested on your Cameleer account. Cameleer is an observability platform for Apache Camel integrations providing real-time route tracing, message inspection, and performance monitoring. If you did not request this verification, please ignore this email or contact your administrator for assistance.</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="hint">This code expires in 10 minutes.</p>
|
||||||
|
<p class="detail">You are receiving this email because a verification was requested on your Cameleer account. Cameleer is an observability platform for Apache Camel integrations providing real-time route tracing, message inspection, and performance monitoring. If you did not request this verification, please ignore this email or contact your administrator for assistance.</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="border-top:1px solid #e8e0d4;padding:16px 24px;text-align:center;">
|
<div class="footer">
|
||||||
<p style="color:#999;font-size:12px;margin:0;">Questions? Contact your administrator</p>
|
<p class="contact">Questions? Contact your administrator</p>
|
||||||
<p style="color:#bbb;font-size:11px;margin:6px 0 0;">Cameleer — Apache Camel observability</p>
|
<p class="tagline">Cameleer — Apache Camel observability</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--[if mso]></td></tr></table><![endif]-->
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -5,30 +5,42 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<title>Your password was reset</title>
|
<title>Your password was reset</title>
|
||||||
|
<style>
|
||||||
|
body { margin:0; padding:0; background:#f5f1eb; }
|
||||||
|
.wrapper { font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; max-width:480px; margin:0 auto; background:#fff; border-radius:8px; overflow:hidden; border:1px solid #e8e0d4; }
|
||||||
|
.header { background:#C6820E; padding:20px 24px; text-align:center; }
|
||||||
|
.header span { font-size:22px; font-weight:700; color:#fff; letter-spacing:0.5px; }
|
||||||
|
.content { padding:32px 24px 24px; }
|
||||||
|
.title { color:#1a1a1a; font-size:16px; font-weight:600; margin:0 0 8px; }
|
||||||
|
.subtitle { color:#444; font-size:14px; line-height:1.6; margin:0 0 16px; }
|
||||||
|
.mfa-note { background:#FDF6EC; border:1px solid #e8e0d4; border-radius:6px; padding:12px 16px; margin:0 0 16px; }
|
||||||
|
.mfa-note p { color:#444; font-size:13px; line-height:1.5; margin:0; }
|
||||||
|
.hint { color:#888; font-size:13px; line-height:1.5; margin:0 0 16px; }
|
||||||
|
.detail { color:#888; font-size:13px; line-height:1.5; margin:0; }
|
||||||
|
.footer { border-top:1px solid #e8e0d4; padding:16px 24px; text-align:center; }
|
||||||
|
.footer p { margin:0; }
|
||||||
|
.footer .contact { color:#999; font-size:12px; }
|
||||||
|
.footer .tagline { color:#bbb; font-size:11px; margin-top:6px; }
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body style="margin:0;padding:0;background:#f5f1eb;">
|
<body>
|
||||||
<!--[if mso]><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center"><![endif]-->
|
<div class="wrapper">
|
||||||
<div style="font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;max-width:480px;margin:0 auto;background:#ffffff;border-radius:8px;overflow:hidden;border:1px solid #e8e0d4;">
|
<div class="header">
|
||||||
<div style="background:#C6820E;padding:20px 24px;text-align:center;">
|
<span>Cameleer.io</span>
|
||||||
<span style="font-size:22px;font-weight:700;color:#ffffff;letter-spacing:0.5px;">Cameleer.io</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:32px 24px 24px;position:relative;overflow:hidden;">
|
<div class="content">
|
||||||
<img src="{{watermarkUrl}}" style="position:absolute;top:-30px;right:-50px;width:320px;height:320px;opacity:0.07;pointer-events:none;border:0;outline:none;" alt="" />
|
<p class="title">Your password was reset</p>
|
||||||
<div style="position:relative;">
|
<p class="subtitle">Your Cameleer account password was successfully changed on {{timestamp}}.</p>
|
||||||
<p style="color:#1a1a1a;font-size:16px;font-weight:600;margin:0 0 8px;">Your password was reset</p>
|
<div class="mfa-note">
|
||||||
<p style="color:#444;font-size:14px;line-height:1.6;margin:0 0 16px;">Your Cameleer account password was successfully changed on {{timestamp}}.</p>
|
<p><strong>Note:</strong> Multi-factor authentication (MFA) was not required for this password reset. We recommend enabling MFA to add an extra layer of security to your account.</p>
|
||||||
<div style="background:#FDF6EC;border:1px solid #e8e0d4;border-radius:6px;padding:12px 16px;margin:0 0 16px;">
|
|
||||||
<p style="color:#444;font-size:13px;line-height:1.5;margin:0;"><strong>Note:</strong> Multi-factor authentication (MFA) was not required for this password reset. We recommend enabling MFA to add an extra layer of security to your account.</p>
|
|
||||||
</div>
|
|
||||||
<p style="color:#888;font-size:13px;line-height:1.5;margin:0 0 16px;">If this wasn't you, contact your administrator immediately.</p>
|
|
||||||
<p style="color:#888;font-size:13px;line-height:1.5;margin:0;">This is an automated security notification from your Cameleer account. Cameleer is an observability platform for Apache Camel integrations providing real-time route tracing, message inspection, and performance monitoring. You are receiving this notification because a password change was completed. For your security, we recommend reviewing your account activity and ensuring your credentials are kept safe.</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="hint">If this wasn't you, contact your administrator immediately.</p>
|
||||||
|
<p class="detail">This is an automated security notification from your Cameleer account. Cameleer is an observability platform for Apache Camel integrations providing real-time route tracing, message inspection, and performance monitoring. You are receiving this notification because a password change was completed. For your security, we recommend reviewing your account activity and ensuring your credentials are kept safe.</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="border-top:1px solid #e8e0d4;padding:16px 24px;text-align:center;">
|
<div class="footer">
|
||||||
<p style="color:#999;font-size:12px;margin:0;">Questions? Contact your administrator</p>
|
<p class="contact">Questions? Contact your administrator</p>
|
||||||
<p style="color:#bbb;font-size:11px;margin:6px 0 0;">Cameleer — Apache Camel observability</p>
|
<p class="tagline">Cameleer — Apache Camel observability</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--[if mso]></td></tr></table><![endif]-->
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -5,32 +5,45 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<title>Your caravan pass is almost ready</title>
|
<title>Your caravan pass is almost ready</title>
|
||||||
|
<style>
|
||||||
|
body { margin:0; padding:0; background:#f5f1eb; }
|
||||||
|
.wrapper { font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; max-width:480px; margin:0 auto; background:#fff; border-radius:8px; overflow:hidden; border:1px solid #e8e0d4; }
|
||||||
|
.header { background:#C6820E; padding:20px 24px; text-align:center; }
|
||||||
|
.header span { font-size:22px; font-weight:700; color:#fff; letter-spacing:0.5px; }
|
||||||
|
.content { padding:32px 24px 24px; }
|
||||||
|
.title { color:#1a1a1a; font-size:16px; font-weight:600; margin:0 0 8px; }
|
||||||
|
.subtitle { color:#444; font-size:14px; line-height:1.6; margin:0 0 24px; }
|
||||||
|
.code-box { text-align:center; margin:0 0 24px; }
|
||||||
|
.code-box div { display:inline-block; background:#FDF6EC; border:2px solid #C6820E; border-radius:8px; padding:16px 32px; }
|
||||||
|
.code-box span { font-size:32px; font-weight:700; letter-spacing:8px; color:#C6820E; font-family:'Courier New',Courier,monospace; }
|
||||||
|
.hint { color:#888; font-size:13px; line-height:1.5; margin:0 0 16px; }
|
||||||
|
.detail { color:#888; font-size:13px; line-height:1.5; margin:0; }
|
||||||
|
.footer { border-top:1px solid #e8e0d4; padding:16px 24px; text-align:center; }
|
||||||
|
.footer p { margin:0; }
|
||||||
|
.footer .contact { color:#999; font-size:12px; }
|
||||||
|
.footer .tagline { color:#bbb; font-size:11px; margin-top:6px; }
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body style="margin:0;padding:0;background:#f5f1eb;">
|
<body>
|
||||||
<!--[if mso]><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center"><![endif]-->
|
<div class="wrapper">
|
||||||
<div style="font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;max-width:480px;margin:0 auto;background:#ffffff;border-radius:8px;overflow:hidden;border:1px solid #e8e0d4;">
|
<div class="header">
|
||||||
<div style="background:#C6820E;padding:20px 24px;text-align:center;">
|
<span>Cameleer.io</span>
|
||||||
<span style="font-size:22px;font-weight:700;color:#ffffff;letter-spacing:0.5px;">Cameleer.io</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:32px 24px 24px;position:relative;overflow:hidden;">
|
<div class="content">
|
||||||
<img src="{{watermarkUrl}}" style="position:absolute;top:-30px;right:-50px;width:320px;height:320px;opacity:0.07;pointer-events:none;border:0;outline:none;" alt="" />
|
<p class="title">Welcome to the caravan!</p>
|
||||||
<div style="position:relative;">
|
<p class="subtitle">Enter this code to verify your email and claim your spot. The dunes wait for no one.</p>
|
||||||
<p style="color:#1a1a1a;font-size:16px;font-weight:600;margin:0 0 8px;">Welcome to the caravan!</p>
|
<div class="code-box">
|
||||||
<p style="color:#444;font-size:14px;line-height:1.6;margin:0 0 24px;">Enter this code to verify your email and claim your spot. The dunes wait for no one.</p>
|
<div>
|
||||||
<div style="text-align:center;margin:0 0 24px;">
|
<span>{{code}}</span>
|
||||||
<div style="display:inline-block;background:#FDF6EC;border:2px solid #C6820E;border-radius:8px;padding:16px 32px;">
|
|
||||||
<span style="font-size:32px;font-weight:700;letter-spacing:8px;color:#C6820E;font-family:'Courier New',Courier,monospace;">{{code}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<p style="color:#888;font-size:13px;line-height:1.5;margin:0 0 16px;">This code expires in 10 minutes. If you didn't request this, you can safely ignore this email — no camels were harmed.</p>
|
|
||||||
<p style="color:#888;font-size:13px;line-height:1.5;margin:0;">Cameleer is an observability platform for Apache Camel integrations. It provides real-time route tracing, message inspection, and performance monitoring to help your team debug and optimize integration flows. Your account gives you access to your dedicated Cameleer instance where you can connect your Camel applications and start monitoring immediately.</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="hint">This code expires in 10 minutes. If you didn't request this, you can safely ignore this email — no camels were harmed.</p>
|
||||||
|
<p class="detail">Cameleer is an observability platform for Apache Camel integrations. It provides real-time route tracing, message inspection, and performance monitoring to help your team debug and optimize integration flows. Your account gives you access to your dedicated Cameleer instance where you can connect your Camel applications and start monitoring immediately.</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="border-top:1px solid #e8e0d4;padding:16px 24px;text-align:center;">
|
<div class="footer">
|
||||||
<p style="color:#999;font-size:12px;margin:0;">Questions? Contact your administrator</p>
|
<p class="contact">Questions? Contact your administrator</p>
|
||||||
<p style="color:#bbb;font-size:11px;margin:6px 0 0;">Cameleer — Apache Camel observability</p>
|
<p class="tagline">Cameleer — Apache Camel observability</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--[if mso]></td></tr></table><![endif]-->
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -5,32 +5,45 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<title>Your Cameleer sign-in code</title>
|
<title>Your Cameleer sign-in code</title>
|
||||||
|
<style>
|
||||||
|
body { margin:0; padding:0; background:#f5f1eb; }
|
||||||
|
.wrapper { font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; max-width:480px; margin:0 auto; background:#fff; border-radius:8px; overflow:hidden; border:1px solid #e8e0d4; }
|
||||||
|
.header { background:#C6820E; padding:20px 24px; text-align:center; }
|
||||||
|
.header span { font-size:22px; font-weight:700; color:#fff; letter-spacing:0.5px; }
|
||||||
|
.content { padding:32px 24px 24px; }
|
||||||
|
.title { color:#1a1a1a; font-size:16px; font-weight:600; margin:0 0 8px; }
|
||||||
|
.subtitle { color:#444; font-size:14px; line-height:1.6; margin:0 0 24px; }
|
||||||
|
.code-box { text-align:center; margin:0 0 24px; }
|
||||||
|
.code-box div { display:inline-block; background:#FDF6EC; border:2px solid #C6820E; border-radius:8px; padding:16px 32px; }
|
||||||
|
.code-box span { font-size:32px; font-weight:700; letter-spacing:8px; color:#C6820E; font-family:'Courier New',Courier,monospace; }
|
||||||
|
.hint { color:#888; font-size:13px; line-height:1.5; margin:0 0 16px; }
|
||||||
|
.detail { color:#888; font-size:13px; line-height:1.5; margin:0; }
|
||||||
|
.footer { border-top:1px solid #e8e0d4; padding:16px 24px; text-align:center; }
|
||||||
|
.footer p { margin:0; }
|
||||||
|
.footer .contact { color:#999; font-size:12px; }
|
||||||
|
.footer .tagline { color:#bbb; font-size:11px; margin-top:6px; }
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body style="margin:0;padding:0;background:#f5f1eb;">
|
<body>
|
||||||
<!--[if mso]><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center"><![endif]-->
|
<div class="wrapper">
|
||||||
<div style="font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;max-width:480px;margin:0 auto;background:#ffffff;border-radius:8px;overflow:hidden;border:1px solid #e8e0d4;">
|
<div class="header">
|
||||||
<div style="background:#C6820E;padding:20px 24px;text-align:center;">
|
<span>Cameleer.io</span>
|
||||||
<span style="font-size:22px;font-weight:700;color:#ffffff;letter-spacing:0.5px;">Cameleer.io</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:32px 24px 24px;position:relative;overflow:hidden;">
|
<div class="content">
|
||||||
<img src="{{watermarkUrl}}" style="position:absolute;top:-30px;right:-50px;width:320px;height:320px;opacity:0.07;pointer-events:none;border:0;outline:none;" alt="" />
|
<p class="title">Back at the oasis already?</p>
|
||||||
<div style="position:relative;">
|
<p class="subtitle">Here's your sign-in code. The caravan master is checking credentials.</p>
|
||||||
<p style="color:#1a1a1a;font-size:16px;font-weight:600;margin:0 0 8px;">Back at the oasis already?</p>
|
<div class="code-box">
|
||||||
<p style="color:#444;font-size:14px;line-height:1.6;margin:0 0 24px;">Here's your sign-in code. The caravan master is checking credentials.</p>
|
<div>
|
||||||
<div style="text-align:center;margin:0 0 24px;">
|
<span>{{code}}</span>
|
||||||
<div style="display:inline-block;background:#FDF6EC;border:2px solid #C6820E;border-radius:8px;padding:16px 32px;">
|
|
||||||
<span style="font-size:32px;font-weight:700;letter-spacing:8px;color:#C6820E;font-family:'Courier New',Courier,monospace;">{{code}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<p style="color:#888;font-size:13px;line-height:1.5;margin:0 0 16px;">This code expires in 10 minutes.</p>
|
|
||||||
<p style="color:#888;font-size:13px;line-height:1.5;margin:0;">You are receiving this email because a sign-in attempt was made on your Cameleer account. Cameleer is an observability platform for Apache Camel integrations providing real-time route tracing, message inspection, and performance monitoring. If you did not initiate this sign-in, please ignore this email or contact your administrator.</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="hint">This code expires in 10 minutes.</p>
|
||||||
|
<p class="detail">You are receiving this email because a sign-in attempt was made on your Cameleer account. Cameleer is an observability platform for Apache Camel integrations providing real-time route tracing, message inspection, and performance monitoring. If you did not initiate this sign-in, please ignore this email or contact your administrator.</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="border-top:1px solid #e8e0d4;padding:16px 24px;text-align:center;">
|
<div class="footer">
|
||||||
<p style="color:#999;font-size:12px;margin:0;">Questions? Contact your administrator</p>
|
<p class="contact">Questions? Contact your administrator</p>
|
||||||
<p style="color:#bbb;font-size:11px;margin:6px 0 0;">Cameleer — Apache Camel observability</p>
|
<p class="tagline">Cameleer — Apache Camel observability</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--[if mso]></td></tr></table><![endif]-->
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -35,24 +35,16 @@ class EmailTemplateLoadingTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void templatesContainWatermarkPlaceholder() throws IOException {
|
void templatesContainHtmlStructure() throws IOException {
|
||||||
for (String path : TEMPLATE_FILES) {
|
for (String path : TEMPLATE_FILES) {
|
||||||
String content = new ClassPathResource(path).getContentAsString(StandardCharsets.UTF_8);
|
String content = new ClassPathResource(path).getContentAsString(StandardCharsets.UTF_8);
|
||||||
assertTrue(content.contains("{{watermarkUrl}}"),
|
assertTrue(content.contains("<!DOCTYPE html>"),
|
||||||
path + " must contain {{watermarkUrl}} placeholder");
|
path + " must contain DOCTYPE declaration");
|
||||||
|
assertTrue(content.contains("<html"),
|
||||||
|
path + " must contain <html> tag");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void watermarkPlaceholderIsReplaced() throws IOException {
|
|
||||||
String content = new ClassPathResource("email-templates/register.html")
|
|
||||||
.getContentAsString(StandardCharsets.UTF_8);
|
|
||||||
String resolved = content.replace("{{watermarkUrl}}",
|
|
||||||
"https://example.com/platform/assets/email-watermark.png");
|
|
||||||
assertFalse(resolved.contains("{{watermarkUrl}}"));
|
|
||||||
assertTrue(resolved.contains("https://example.com/platform/assets/email-watermark.png"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void templatesContainBrandElements() throws IOException {
|
void templatesContainBrandElements() throws IOException {
|
||||||
for (String path : TEMPLATE_FILES) {
|
for (String path : TEMPLATE_FILES) {
|
||||||
|
|||||||
Reference in New Issue
Block a user