|
|
|
|
@@ -84,6 +84,74 @@ func (s *EmailService) SendEmailWithAttachment(to, subject, htmlBody, textBody s
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// baseEmailTemplate returns the styled email wrapper
|
|
|
|
|
func baseEmailTemplate() string {
|
|
|
|
|
return `<!DOCTYPE html>
|
|
|
|
|
<html lang="en">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
|
|
<title>%s</title>
|
|
|
|
|
<!--[if mso]>
|
|
|
|
|
<noscript>
|
|
|
|
|
<xml>
|
|
|
|
|
<o:OfficeDocumentSettings>
|
|
|
|
|
<o:PixelsPerInch>96</o:PixelsPerInch>
|
|
|
|
|
</o:OfficeDocumentSettings>
|
|
|
|
|
</xml>
|
|
|
|
|
</noscript>
|
|
|
|
|
<![endif]-->
|
|
|
|
|
</head>
|
|
|
|
|
<body style="margin: 0; padding: 0; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: linear-gradient(180deg, #0F172A 0%%, #1E293B 100%%); -webkit-font-smoothing: antialiased;">
|
|
|
|
|
<table role="presentation" width="100%%" cellspacing="0" cellpadding="0" style="background: linear-gradient(180deg, #0F172A 0%%, #1E293B 100%%);">
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="padding: 40px 20px;">
|
|
|
|
|
<table role="presentation" width="600" cellspacing="0" cellpadding="0" style="max-width: 600px; margin: 0 auto; background: #1E293B; border-radius: 16px; overflow: hidden; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.3);">
|
|
|
|
|
%s
|
|
|
|
|
</table>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
</body>
|
|
|
|
|
</html>`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// emailIconURL is the URL for the email icon
|
|
|
|
|
const emailIconURL = "https://casera.app/images/icon.png"
|
|
|
|
|
|
|
|
|
|
// emailHeader returns the gradient header section with logo
|
|
|
|
|
func emailHeader(title string) string {
|
|
|
|
|
return fmt.Sprintf(`
|
|
|
|
|
<!-- Header -->
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: linear-gradient(135deg, #0079FF 0%%, #5AC7F9 50%%, #14B8A6 100%%); padding: 40px 30px; text-align: center;">
|
|
|
|
|
<!-- Logo Icon -->
|
|
|
|
|
<table role="presentation" cellspacing="0" cellpadding="0" style="margin: 0 auto 16px auto;">
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: rgba(255, 255, 255, 0.15); border-radius: 20px; padding: 4px;">
|
|
|
|
|
<img src="%s" alt="Casera" width="64" height="64" style="display: block; border-radius: 16px; border: 0;" />
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
<h1 style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 28px; font-weight: 800; color: #FFFFFF; margin: 0; letter-spacing: -0.5px;">Casera</h1>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 20px; font-weight: 600; color: rgba(255, 255, 255, 0.95); margin: 12px 0 0 0;">%s</p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>`, emailIconURL, title)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// emailFooter returns the footer section
|
|
|
|
|
func emailFooter(year int) string {
|
|
|
|
|
return fmt.Sprintf(`
|
|
|
|
|
<!-- Footer -->
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: #0F172A; padding: 30px; text-align: center;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 12px; color: rgba(255, 255, 255, 0.5); margin: 0;">© %d Casera. All rights reserved.</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 12px; color: rgba(255, 255, 255, 0.4); margin: 12px 0 0 0;">Never miss home maintenance again.</p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>`, year)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SendWelcomeEmail sends a welcome email with verification code
|
|
|
|
|
func (s *EmailService) SendWelcomeEmail(to, firstName, code string) error {
|
|
|
|
|
subject := "Welcome to Casera - Verify Your Email"
|
|
|
|
|
@@ -93,37 +161,35 @@ func (s *EmailService) SendWelcomeEmail(to, firstName, code string) error {
|
|
|
|
|
name = "there"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(`
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
<style>
|
|
|
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
|
|
|
|
|
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
|
|
|
.header { text-align: center; padding: 20px 0; }
|
|
|
|
|
.code { background: #f4f4f4; padding: 20px; text-align: center; font-size: 32px; font-weight: bold; letter-spacing: 8px; border-radius: 8px; margin: 20px 0; }
|
|
|
|
|
.footer { text-align: center; color: #666; font-size: 12px; margin-top: 40px; }
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div class="container">
|
|
|
|
|
<div class="header">
|
|
|
|
|
<h1>Welcome to Casera!</h1>
|
|
|
|
|
</div>
|
|
|
|
|
<p>Hi %s,</p>
|
|
|
|
|
<p>Thank you for creating a Casera account. To complete your registration, please verify your email address by entering the following code:</p>
|
|
|
|
|
<div class="code">%s</div>
|
|
|
|
|
<p>This code will expire in 24 hours.</p>
|
|
|
|
|
<p>If you didn't create a Casera account, you can safely ignore this email.</p>
|
|
|
|
|
<p>Best regards,<br>The Casera Team</p>
|
|
|
|
|
<div class="footer">
|
|
|
|
|
<p>© %d Casera. All rights reserved.</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|
|
|
|
|
`, name, code, time.Now().Year())
|
|
|
|
|
bodyContent := fmt.Sprintf(`
|
|
|
|
|
%s
|
|
|
|
|
<!-- Body -->
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: #FFFFFF; padding: 40px 30px;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 18px; font-weight: 600; color: #1a1a1a; margin: 0 0 20px 0;">Hi %s,</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 16px; line-height: 1.6; color: #4B5563; margin: 0 0 20px 0;">Thank you for creating a Casera account! To complete your registration, please verify your email address by entering the code below:</p>
|
|
|
|
|
|
|
|
|
|
<!-- Code Box -->
|
|
|
|
|
<table role="presentation" width="100%%" cellspacing="0" cellpadding="0">
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: linear-gradient(135deg, rgba(0, 121, 255, 0.1) 0%%, rgba(20, 184, 166, 0.1) 100%%); border: 2px solid rgba(0, 121, 255, 0.2); border-radius: 12px; padding: 24px; text-align: center;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 36px; font-weight: 800; letter-spacing: 8px; color: #0079FF; margin: 0;">%s</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 13px; color: #9CA3AF; margin: 12px 0 0 0;">This code will expire in 24 hours</p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; line-height: 1.6; color: #6B7280; margin: 24px 0 0 0;">If you didn't create a Casera account, you can safely ignore this email.</p>
|
|
|
|
|
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; color: #6B7280; margin: 30px 0 0 0;">Best regards,<br><strong style="color: #1a1a1a;">The Casera Team</strong></p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
%s`,
|
|
|
|
|
emailHeader("Welcome!"),
|
|
|
|
|
name, code,
|
|
|
|
|
emailFooter(time.Now().Year()))
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(baseEmailTemplate(), subject, bodyContent)
|
|
|
|
|
|
|
|
|
|
textBody := fmt.Sprintf(`
|
|
|
|
|
Welcome to Casera!
|
|
|
|
|
@@ -154,44 +220,38 @@ func (s *EmailService) SendAppleWelcomeEmail(to, firstName string) error {
|
|
|
|
|
name = "there"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(`
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
<style>
|
|
|
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
|
|
|
|
|
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
|
|
|
.header { text-align: center; padding: 20px 0; }
|
|
|
|
|
.cta { background: #07A0C3; color: white; padding: 15px 30px; text-decoration: none; border-radius: 8px; display: inline-block; margin: 20px 0; }
|
|
|
|
|
.features { background: #f8f9fa; padding: 20px; border-radius: 8px; margin: 20px 0; }
|
|
|
|
|
.feature { margin: 10px 0; }
|
|
|
|
|
.footer { text-align: center; color: #666; font-size: 12px; margin-top: 40px; }
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div class="container">
|
|
|
|
|
<div class="header">
|
|
|
|
|
<h1>Welcome to Casera!</h1>
|
|
|
|
|
</div>
|
|
|
|
|
<p>Hi %s,</p>
|
|
|
|
|
<p>Thank you for joining Casera! Your account has been created and you're ready to start managing your properties.</p>
|
|
|
|
|
<div class="features">
|
|
|
|
|
<h3>Here's what you can do with Casera:</h3>
|
|
|
|
|
<div class="feature">🏠 <strong>Manage Properties</strong> - Track all your homes and rentals in one place</div>
|
|
|
|
|
<div class="feature">✅ <strong>Task Management</strong> - Never miss maintenance with smart scheduling</div>
|
|
|
|
|
<div class="feature">👷 <strong>Contractor Directory</strong> - Keep your trusted pros organized</div>
|
|
|
|
|
<div class="feature">📄 <strong>Document Storage</strong> - Store warranties, manuals, and important records</div>
|
|
|
|
|
</div>
|
|
|
|
|
<p>If you have any questions, feel free to reach out to us at support@casera.app.</p>
|
|
|
|
|
<p>Best regards,<br>The Casera Team</p>
|
|
|
|
|
<div class="footer">
|
|
|
|
|
<p>© %d Casera. All rights reserved.</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|
|
|
|
|
`, name, time.Now().Year())
|
|
|
|
|
bodyContent := fmt.Sprintf(`
|
|
|
|
|
%s
|
|
|
|
|
<!-- Body -->
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: #FFFFFF; padding: 40px 30px;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 18px; font-weight: 600; color: #1a1a1a; margin: 0 0 20px 0;">Hi %s,</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 16px; line-height: 1.6; color: #4B5563; margin: 0 0 24px 0;">Thank you for joining Casera! Your account has been created and you're ready to start managing your properties.</p>
|
|
|
|
|
|
|
|
|
|
<!-- Features Box -->
|
|
|
|
|
<table role="presentation" width="100%%" cellspacing="0" cellpadding="0">
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: #F8FAFC; border-radius: 12px; padding: 24px;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 16px; font-weight: 700; color: #1a1a1a; margin: 0 0 16px 0;">Here's what you can do with Casera:</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; color: #4B5563; margin: 12px 0;">🏠 <strong>Manage Properties</strong> - Track all your homes and rentals in one place</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; color: #4B5563; margin: 12px 0;">✅ <strong>Task Management</strong> - Never miss maintenance with smart scheduling</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; color: #4B5563; margin: 12px 0;">👷 <strong>Contractor Directory</strong> - Keep your trusted pros organized</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; color: #4B5563; margin: 12px 0;">📄 <strong>Document Storage</strong> - Store warranties, manuals, and important records</p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; line-height: 1.6; color: #6B7280; margin: 24px 0 0 0;">If you have any questions, feel free to reach out to us at support@casera.app.</p>
|
|
|
|
|
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; color: #6B7280; margin: 30px 0 0 0;">Best regards,<br><strong style="color: #1a1a1a;">The Casera Team</strong></p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
%s`,
|
|
|
|
|
emailHeader("Welcome!"),
|
|
|
|
|
name,
|
|
|
|
|
emailFooter(time.Now().Year()))
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(baseEmailTemplate(), subject, bodyContent)
|
|
|
|
|
|
|
|
|
|
textBody := fmt.Sprintf(`
|
|
|
|
|
Welcome to Casera!
|
|
|
|
|
@@ -224,34 +284,35 @@ func (s *EmailService) SendVerificationEmail(to, firstName, code string) error {
|
|
|
|
|
name = "there"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(`
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
<style>
|
|
|
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
|
|
|
|
|
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
|
|
|
.code { background: #f4f4f4; padding: 20px; text-align: center; font-size: 32px; font-weight: bold; letter-spacing: 8px; border-radius: 8px; margin: 20px 0; }
|
|
|
|
|
.footer { text-align: center; color: #666; font-size: 12px; margin-top: 40px; }
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div class="container">
|
|
|
|
|
<h1>Verify Your Email</h1>
|
|
|
|
|
<p>Hi %s,</p>
|
|
|
|
|
<p>Please use the following code to verify your email address:</p>
|
|
|
|
|
<div class="code">%s</div>
|
|
|
|
|
<p>This code will expire in 24 hours.</p>
|
|
|
|
|
<p>If you didn't request this, you can safely ignore this email.</p>
|
|
|
|
|
<p>Best regards,<br>The Casera Team</p>
|
|
|
|
|
<div class="footer">
|
|
|
|
|
<p>© %d Casera. All rights reserved.</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|
|
|
|
|
`, name, code, time.Now().Year())
|
|
|
|
|
bodyContent := fmt.Sprintf(`
|
|
|
|
|
%s
|
|
|
|
|
<!-- Body -->
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: #FFFFFF; padding: 40px 30px;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 18px; font-weight: 600; color: #1a1a1a; margin: 0 0 20px 0;">Hi %s,</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 16px; line-height: 1.6; color: #4B5563; margin: 0 0 20px 0;">Please use the following code to verify your email address:</p>
|
|
|
|
|
|
|
|
|
|
<!-- Code Box -->
|
|
|
|
|
<table role="presentation" width="100%%" cellspacing="0" cellpadding="0">
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: linear-gradient(135deg, rgba(0, 121, 255, 0.1) 0%%, rgba(20, 184, 166, 0.1) 100%%); border: 2px solid rgba(0, 121, 255, 0.2); border-radius: 12px; padding: 24px; text-align: center;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 36px; font-weight: 800; letter-spacing: 8px; color: #0079FF; margin: 0;">%s</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 13px; color: #9CA3AF; margin: 12px 0 0 0;">This code will expire in 24 hours</p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; line-height: 1.6; color: #6B7280; margin: 24px 0 0 0;">If you didn't request this, you can safely ignore this email.</p>
|
|
|
|
|
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; color: #6B7280; margin: 30px 0 0 0;">Best regards,<br><strong style="color: #1a1a1a;">The Casera Team</strong></p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
%s`,
|
|
|
|
|
emailHeader("Verify Your Email"),
|
|
|
|
|
name, code,
|
|
|
|
|
emailFooter(time.Now().Year()))
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(baseEmailTemplate(), subject, bodyContent)
|
|
|
|
|
|
|
|
|
|
textBody := fmt.Sprintf(`
|
|
|
|
|
Verify Your Email
|
|
|
|
|
@@ -282,37 +343,43 @@ func (s *EmailService) SendPasswordResetEmail(to, firstName, code string) error
|
|
|
|
|
name = "there"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(`
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
<style>
|
|
|
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
|
|
|
|
|
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
|
|
|
.code { background: #f4f4f4; padding: 20px; text-align: center; font-size: 32px; font-weight: bold; letter-spacing: 8px; border-radius: 8px; margin: 20px 0; }
|
|
|
|
|
.warning { background: #fff3cd; border: 1px solid #ffc107; padding: 15px; border-radius: 8px; margin: 20px 0; }
|
|
|
|
|
.footer { text-align: center; color: #666; font-size: 12px; margin-top: 40px; }
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div class="container">
|
|
|
|
|
<h1>Password Reset Request</h1>
|
|
|
|
|
<p>Hi %s,</p>
|
|
|
|
|
<p>We received a request to reset your password. Use the following code to complete the reset:</p>
|
|
|
|
|
<div class="code">%s</div>
|
|
|
|
|
<p>This code will expire in 15 minutes.</p>
|
|
|
|
|
<div class="warning">
|
|
|
|
|
<strong>Security Notice:</strong> If you didn't request a password reset, please ignore this email. Your password will remain unchanged.
|
|
|
|
|
</div>
|
|
|
|
|
<p>Best regards,<br>The Casera Team</p>
|
|
|
|
|
<div class="footer">
|
|
|
|
|
<p>© %d Casera. All rights reserved.</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|
|
|
|
|
`, name, code, time.Now().Year())
|
|
|
|
|
bodyContent := fmt.Sprintf(`
|
|
|
|
|
%s
|
|
|
|
|
<!-- Body -->
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: #FFFFFF; padding: 40px 30px;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 18px; font-weight: 600; color: #1a1a1a; margin: 0 0 20px 0;">Hi %s,</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 16px; line-height: 1.6; color: #4B5563; margin: 0 0 20px 0;">We received a request to reset your password. Use the following code to complete the reset:</p>
|
|
|
|
|
|
|
|
|
|
<!-- Code Box -->
|
|
|
|
|
<table role="presentation" width="100%%" cellspacing="0" cellpadding="0">
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: linear-gradient(135deg, rgba(0, 121, 255, 0.1) 0%%, rgba(20, 184, 166, 0.1) 100%%); border: 2px solid rgba(0, 121, 255, 0.2); border-radius: 12px; padding: 24px; text-align: center;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 36px; font-weight: 800; letter-spacing: 8px; color: #0079FF; margin: 0;">%s</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 13px; color: #9CA3AF; margin: 12px 0 0 0;">This code will expire in 15 minutes</p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
<!-- Warning Box -->
|
|
|
|
|
<table role="presentation" width="100%%" cellspacing="0" cellpadding="0" style="margin: 24px 0;">
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: linear-gradient(135deg, rgba(255, 148, 0, 0.1) 0%%, rgba(236, 72, 153, 0.05) 100%%); border-left: 4px solid #FF9400; border-radius: 8px; padding: 16px 20px;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; font-weight: 700; color: #E68600; margin: 0 0 8px 0;">Security Notice</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; color: #4B5563; margin: 0;">If you didn't request a password reset, please ignore this email. Your password will remain unchanged.</p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; color: #6B7280; margin: 30px 0 0 0;">Best regards,<br><strong style="color: #1a1a1a;">The Casera Team</strong></p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
%s`,
|
|
|
|
|
emailHeader("Password Reset"),
|
|
|
|
|
name, code,
|
|
|
|
|
emailFooter(time.Now().Year()))
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(baseEmailTemplate(), subject, bodyContent)
|
|
|
|
|
|
|
|
|
|
textBody := fmt.Sprintf(`
|
|
|
|
|
Password Reset Request
|
|
|
|
|
@@ -343,34 +410,35 @@ func (s *EmailService) SendPasswordChangedEmail(to, firstName string) error {
|
|
|
|
|
name = "there"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(`
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
<style>
|
|
|
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
|
|
|
|
|
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
|
|
|
.warning { background: #fff3cd; border: 1px solid #ffc107; padding: 15px; border-radius: 8px; margin: 20px 0; }
|
|
|
|
|
.footer { text-align: center; color: #666; font-size: 12px; margin-top: 40px; }
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div class="container">
|
|
|
|
|
<h1>Password Changed</h1>
|
|
|
|
|
<p>Hi %s,</p>
|
|
|
|
|
<p>Your Casera password was successfully changed on %s.</p>
|
|
|
|
|
<div class="warning">
|
|
|
|
|
<strong>Didn't make this change?</strong> If you didn't change your password, please contact us immediately at support@casera.app or reset your password.
|
|
|
|
|
</div>
|
|
|
|
|
<p>Best regards,<br>The Casera Team</p>
|
|
|
|
|
<div class="footer">
|
|
|
|
|
<p>© %d Casera. All rights reserved.</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|
|
|
|
|
`, name, time.Now().UTC().Format("January 2, 2006 at 3:04 PM UTC"), time.Now().Year())
|
|
|
|
|
changeTime := time.Now().UTC().Format("January 2, 2006 at 3:04 PM UTC")
|
|
|
|
|
|
|
|
|
|
bodyContent := fmt.Sprintf(`
|
|
|
|
|
%s
|
|
|
|
|
<!-- Body -->
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: #FFFFFF; padding: 40px 30px;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 18px; font-weight: 600; color: #1a1a1a; margin: 0 0 20px 0;">Hi %s,</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 16px; line-height: 1.6; color: #4B5563; margin: 0 0 24px 0;">Your Casera password was successfully changed on <strong>%s</strong>.</p>
|
|
|
|
|
|
|
|
|
|
<!-- Warning Box -->
|
|
|
|
|
<table role="presentation" width="100%%" cellspacing="0" cellpadding="0" style="margin: 24px 0;">
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: linear-gradient(135deg, rgba(255, 148, 0, 0.1) 0%%, rgba(236, 72, 153, 0.05) 100%%); border-left: 4px solid #FF9400; border-radius: 8px; padding: 16px 20px;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; font-weight: 700; color: #E68600; margin: 0 0 8px 0;">Didn't make this change?</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; color: #4B5563; margin: 0;">If you didn't change your password, please contact us immediately at support@casera.app or reset your password.</p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; color: #6B7280; margin: 30px 0 0 0;">Best regards,<br><strong style="color: #1a1a1a;">The Casera Team</strong></p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
%s`,
|
|
|
|
|
emailHeader("Password Changed"),
|
|
|
|
|
name, changeTime,
|
|
|
|
|
emailFooter(time.Now().Year()))
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(baseEmailTemplate(), subject, bodyContent)
|
|
|
|
|
|
|
|
|
|
textBody := fmt.Sprintf(`
|
|
|
|
|
Password Changed
|
|
|
|
|
@@ -383,7 +451,7 @@ DIDN'T MAKE THIS CHANGE? If you didn't change your password, please contact us i
|
|
|
|
|
|
|
|
|
|
Best regards,
|
|
|
|
|
The Casera Team
|
|
|
|
|
`, name, time.Now().UTC().Format("January 2, 2006 at 3:04 PM UTC"))
|
|
|
|
|
`, name, changeTime)
|
|
|
|
|
|
|
|
|
|
return s.SendEmail(to, subject, htmlBody, textBody)
|
|
|
|
|
}
|
|
|
|
|
@@ -397,40 +465,35 @@ func (s *EmailService) SendTaskCompletedEmail(to, recipientName, taskTitle, comp
|
|
|
|
|
name = "there"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(`
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
<style>
|
|
|
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
|
|
|
|
|
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
|
|
|
.header { text-align: center; padding: 20px 0; }
|
|
|
|
|
.task-box { background: #d4edda; border: 1px solid #c3e6cb; padding: 20px; border-radius: 8px; margin: 20px 0; }
|
|
|
|
|
.task-title { font-size: 18px; font-weight: bold; color: #155724; margin: 0; }
|
|
|
|
|
.task-meta { color: #666; font-size: 14px; margin-top: 10px; }
|
|
|
|
|
.footer { text-align: center; color: #666; font-size: 12px; margin-top: 40px; }
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div class="container">
|
|
|
|
|
<div class="header">
|
|
|
|
|
<h1>Task Completed!</h1>
|
|
|
|
|
</div>
|
|
|
|
|
<p>Hi %s,</p>
|
|
|
|
|
<p>A task has been completed at <strong>%s</strong>:</p>
|
|
|
|
|
<div class="task-box">
|
|
|
|
|
<p class="task-title">%s</p>
|
|
|
|
|
<p class="task-meta">Completed by: %s<br>Completed on: %s</p>
|
|
|
|
|
</div>
|
|
|
|
|
<p>Best regards,<br>The Casera Team</p>
|
|
|
|
|
<div class="footer">
|
|
|
|
|
<p>© %d Casera. All rights reserved.</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|
|
|
|
|
`, name, residenceName, taskTitle, completedByName, time.Now().UTC().Format("January 2, 2006 at 3:04 PM"), time.Now().Year())
|
|
|
|
|
completedTime := time.Now().UTC().Format("January 2, 2006 at 3:04 PM")
|
|
|
|
|
|
|
|
|
|
bodyContent := fmt.Sprintf(`
|
|
|
|
|
%s
|
|
|
|
|
<!-- Body -->
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: #FFFFFF; padding: 40px 30px;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 18px; font-weight: 600; color: #1a1a1a; margin: 0 0 20px 0;">Hi %s,</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 16px; line-height: 1.6; color: #4B5563; margin: 0 0 24px 0;">A task has been completed at <strong>%s</strong>:</p>
|
|
|
|
|
|
|
|
|
|
<!-- Success Box -->
|
|
|
|
|
<table role="presentation" width="100%%" cellspacing="0" cellpadding="0">
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: linear-gradient(135deg, rgba(34, 197, 94, 0.1) 0%%, rgba(20, 184, 166, 0.1) 100%%); border-left: 4px solid #22C55E; border-radius: 8px; padding: 20px;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 18px; font-weight: 700; color: #15803d; margin: 0 0 8px 0;">%s</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 13px; color: #6B7280; margin: 8px 0 0 0;">Completed by: %s<br>Completed on: %s</p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; color: #6B7280; margin: 30px 0 0 0;">Best regards,<br><strong style="color: #1a1a1a;">The Casera Team</strong></p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
%s`,
|
|
|
|
|
emailHeader("Task Completed!"),
|
|
|
|
|
name, residenceName, taskTitle, completedByName, completedTime,
|
|
|
|
|
emailFooter(time.Now().Year()))
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(baseEmailTemplate(), subject, bodyContent)
|
|
|
|
|
|
|
|
|
|
textBody := fmt.Sprintf(`
|
|
|
|
|
Task Completed!
|
|
|
|
|
@@ -445,7 +508,7 @@ Completed on: %s
|
|
|
|
|
|
|
|
|
|
Best regards,
|
|
|
|
|
The Casera Team
|
|
|
|
|
`, name, residenceName, taskTitle, completedByName, time.Now().UTC().Format("January 2, 2006 at 3:04 PM"))
|
|
|
|
|
`, name, residenceName, taskTitle, completedByName, completedTime)
|
|
|
|
|
|
|
|
|
|
return s.SendEmail(to, subject, htmlBody, textBody)
|
|
|
|
|
}
|
|
|
|
|
@@ -459,66 +522,54 @@ func (s *EmailService) SendTasksReportEmail(to, recipientName, residenceName str
|
|
|
|
|
name = "there"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(`
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
<style>
|
|
|
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
|
|
|
|
|
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
|
|
|
.header { text-align: center; padding: 20px 0; }
|
|
|
|
|
.summary-box { background: #f8f9fa; border: 1px solid #e9ecef; padding: 20px; border-radius: 8px; margin: 20px 0; }
|
|
|
|
|
.summary-grid { display: flex; flex-wrap: wrap; gap: 20px; }
|
|
|
|
|
.summary-item { flex: 1; min-width: 80px; text-align: center; }
|
|
|
|
|
.summary-number { font-size: 28px; font-weight: bold; color: #333; }
|
|
|
|
|
.summary-label { font-size: 12px; color: #666; text-transform: uppercase; }
|
|
|
|
|
.completed { color: #28a745; }
|
|
|
|
|
.pending { color: #ffc107; }
|
|
|
|
|
.overdue { color: #dc3545; }
|
|
|
|
|
.footer { text-align: center; color: #666; font-size: 12px; margin-top: 40px; }
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div class="container">
|
|
|
|
|
<div class="header">
|
|
|
|
|
<h1>Tasks Report</h1>
|
|
|
|
|
<p style="color: #666; margin: 0;">%s</p>
|
|
|
|
|
</div>
|
|
|
|
|
<p>Hi %s,</p>
|
|
|
|
|
<p>Here's your tasks report for <strong>%s</strong>. The full report is attached as a PDF.</p>
|
|
|
|
|
<div class="summary-box">
|
|
|
|
|
<h3 style="margin-top: 0;">Summary</h3>
|
|
|
|
|
<table width="100%%" cellpadding="10" cellspacing="0">
|
|
|
|
|
<tr>
|
|
|
|
|
<td align="center" style="border-right: 1px solid #e9ecef;">
|
|
|
|
|
<div class="summary-number">%d</div>
|
|
|
|
|
<div class="summary-label">Total Tasks</div>
|
|
|
|
|
</td>
|
|
|
|
|
<td align="center" style="border-right: 1px solid #e9ecef;">
|
|
|
|
|
<div class="summary-number completed">%d</div>
|
|
|
|
|
<div class="summary-label">Completed</div>
|
|
|
|
|
</td>
|
|
|
|
|
<td align="center" style="border-right: 1px solid #e9ecef;">
|
|
|
|
|
<div class="summary-number pending">%d</div>
|
|
|
|
|
<div class="summary-label">Pending</div>
|
|
|
|
|
</td>
|
|
|
|
|
<td align="center">
|
|
|
|
|
<div class="summary-number overdue">%d</div>
|
|
|
|
|
<div class="summary-label">Overdue</div>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
<p>Open the attached PDF for the complete list of tasks with details.</p>
|
|
|
|
|
<p>Best regards,<br>The Casera Team</p>
|
|
|
|
|
<div class="footer">
|
|
|
|
|
<p>© %d Casera. All rights reserved.</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|
|
|
|
|
`, residenceName, name, residenceName, totalTasks, completed, pending, overdue, time.Now().Year())
|
|
|
|
|
bodyContent := fmt.Sprintf(`
|
|
|
|
|
%s
|
|
|
|
|
<!-- Body -->
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: #FFFFFF; padding: 40px 30px;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 18px; font-weight: 600; color: #1a1a1a; margin: 0 0 20px 0;">Hi %s,</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 16px; line-height: 1.6; color: #4B5563; margin: 0 0 24px 0;">Here's your tasks report for <strong>%s</strong>. The full report is attached as a PDF.</p>
|
|
|
|
|
|
|
|
|
|
<!-- Summary Box -->
|
|
|
|
|
<table role="presentation" width="100%%" cellspacing="0" cellpadding="0" style="margin: 24px 0;">
|
|
|
|
|
<tr>
|
|
|
|
|
<td style="background: #F8FAFC; border-radius: 12px; padding: 24px;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 16px; font-weight: 700; color: #1a1a1a; margin: 0 0 16px 0;">Summary</p>
|
|
|
|
|
<table role="presentation" width="100%%" cellspacing="0" cellpadding="0">
|
|
|
|
|
<tr>
|
|
|
|
|
<td width="25%%" style="text-align: center; padding: 12px;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 28px; font-weight: 800; color: #1a1a1a; margin: 0;">%d</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 11px; font-weight: 600; color: #9CA3AF; text-transform: uppercase; letter-spacing: 0.5px; margin: 4px 0 0 0;">Total</p>
|
|
|
|
|
</td>
|
|
|
|
|
<td width="25%%" style="text-align: center; padding: 12px; border-left: 1px solid #E5E7EB;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 28px; font-weight: 800; color: #22C55E; margin: 0;">%d</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 11px; font-weight: 600; color: #9CA3AF; text-transform: uppercase; letter-spacing: 0.5px; margin: 4px 0 0 0;">Completed</p>
|
|
|
|
|
</td>
|
|
|
|
|
<td width="25%%" style="text-align: center; padding: 12px; border-left: 1px solid #E5E7EB;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 28px; font-weight: 800; color: #FF9400; margin: 0;">%d</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 11px; font-weight: 600; color: #9CA3AF; text-transform: uppercase; letter-spacing: 0.5px; margin: 4px 0 0 0;">Pending</p>
|
|
|
|
|
</td>
|
|
|
|
|
<td width="25%%" style="text-align: center; padding: 12px; border-left: 1px solid #E5E7EB;">
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 28px; font-weight: 800; color: #EF4444; margin: 0;">%d</p>
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 11px; font-weight: 600; color: #9CA3AF; text-transform: uppercase; letter-spacing: 0.5px; margin: 4px 0 0 0;">Overdue</p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; line-height: 1.6; color: #6B7280; margin: 0 0 24px 0;">Open the attached PDF for the complete list of tasks with details.</p>
|
|
|
|
|
|
|
|
|
|
<p style="font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; color: #6B7280; margin: 30px 0 0 0;">Best regards,<br><strong style="color: #1a1a1a;">The Casera Team</strong></p>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
%s`,
|
|
|
|
|
emailHeader("Tasks Report"),
|
|
|
|
|
name, residenceName, totalTasks, completed, pending, overdue,
|
|
|
|
|
emailFooter(time.Now().Year()))
|
|
|
|
|
|
|
|
|
|
htmlBody := fmt.Sprintf(baseEmailTemplate(), subject, bodyContent)
|
|
|
|
|
|
|
|
|
|
textBody := fmt.Sprintf(`
|
|
|
|
|
Tasks Report for %s
|
|
|
|
|
|