Improved email reminders

This commit is contained in:
Corey Blais
2026-04-21 16:20:03 -04:00
parent 6f5953db9e
commit 5ba40586ed
5 changed files with 31 additions and 11 deletions
+1
View File
@@ -9,6 +9,7 @@ TRUST_PROXY=
ADMIN_EMAILS=corey@blaishome.online
RESCUE_STATUS_NOTIFICATION_EMAIL=appadmin@flockpal.app
DEFAULT_BIRD_PHOTO_PATH=/app/assets/yoda.png
FLOCKPAL_EMAIL_LOGO_PATH=/app/assets/flockpal-logo.png
MILESTONE_REMINDERS_ENABLED=true
MILESTONE_REMINDER_TIME_ZONE=America/New_York
STRIPE_SECRET_KEY=
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

+28 -11
View File
@@ -838,8 +838,21 @@ const getMilestoneYearCount = (reminder: BirdMilestoneReminderCandidateRow) => {
return Number.isFinite(sourceYear) ? Math.max(0, reminder.reminder_year - sourceYear) : 0;
};
const getFlockPalLogoSvg = () =>
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><linearGradient id="featherFill" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#cb3a35"/><stop offset="30%" stop-color="#f0b63f"/><stop offset="58%" stop-color="#238a5a"/><stop offset="100%" stop-color="#2769b3"/></linearGradient></defs><path d="M50.8 10.4C37.9 10.3 27 18.5 22.7 31.1c-3.1 9.1-2.1 18.5-8.6 24.8c-1.5 1.5-0.2 4 1.9 3.6c8.4-1.5 14.6-6.7 18.6-13.7c1 0.5 2.2 0.8 3.4 0.8c3.5 0 6.5-2.3 7.5-5.4c1.9-0.4 3.7-1.3 5.1-2.7c2-2 3-4.6 3.1-7.2c3.3-5.8 4.9-12.9 1.4-20.2c-0.7-1.3-2-0.7-4.3-0.7Z" fill="url(#featherFill)"/><path d="M18 56c8.5-3.4 14.2-9.8 18.1-17.8M26.9 48.9c6.9-7.2 13.5-14.8 20.3-22.1M31.8 41.2c6.4-1.3 12.1-4.6 16.5-9.4M36.8 33.8c4.9-0.9 9.2-3.4 12.6-7.1" fill="none" stroke="#fff8ef" stroke-linecap="round" stroke-width="2.6"/><path d="M18 56c8.5-3.4 14.2-9.8 18.1-17.8" fill="none" stroke="#63562d" stroke-linecap="round" stroke-width="2.2"/></svg>`;
const getFlockPalLogoAttachment = () => {
const logoPath = process.env.FLOCKPAL_EMAIL_LOGO_PATH?.trim() || path.join(process.cwd(), 'assets', 'flockpal-logo.png');
if (!existsSync(logoPath)) {
console.warn(`Unable to load FlockPal email logo from ${logoPath}`);
return null;
}
return {
filename: 'flockpal-logo.png',
path: logoPath,
cid: 'flockpal-logo',
contentDisposition: 'inline' as const,
};
};
const parseDataImage = (dataUrl: string) => {
const match = /^data:(image\/[a-zA-Z0-9.+-]+);base64,(.+)$/.exec(dataUrl);
@@ -865,6 +878,7 @@ const getDefaultBirdPhotoAttachment = () => {
filename: 'yoda.png',
path: defaultPhotoPath,
cid: 'flockpal-default-bird-photo',
contentDisposition: 'inline' as const,
};
};
@@ -1126,24 +1140,23 @@ const sendBirdMilestoneReminderNotification = async ({
}
const copy = buildBirdMilestoneReminderCopy(reminder);
const attachments: NonNullable<SendMailOptions['attachments']> = [
{
filename: 'flockpal-logo.svg',
content: getFlockPalLogoSvg(),
contentType: 'image/svg+xml',
cid: 'flockpal-logo',
},
];
const attachments: NonNullable<SendMailOptions['attachments']> = [];
const logoAttachment = getFlockPalLogoAttachment();
const uploadedBirdPhoto = reminder.photo_data_url ? parseDataImage(reminder.photo_data_url) : null;
const defaultBirdPhoto = uploadedBirdPhoto ? null : getDefaultBirdPhotoAttachment();
const birdPhotoCid = uploadedBirdPhoto ? 'bird-photo' : defaultBirdPhoto ? defaultBirdPhoto.cid : '';
if (logoAttachment) {
attachments.push(logoAttachment);
}
if (uploadedBirdPhoto) {
attachments.push({
filename: `${reminder.name.replace(/[^a-z0-9_-]+/gi, '-').toLowerCase() || 'bird'}-photo`,
content: uploadedBirdPhoto.content,
contentType: uploadedBirdPhoto.contentType,
cid: birdPhotoCid,
contentDisposition: 'inline',
});
} else if (defaultBirdPhoto) {
attachments.push(defaultBirdPhoto);
@@ -1181,7 +1194,11 @@ const sendBirdMilestoneReminderNotification = async ({
<div style="margin: 0; padding: 28px; background: #f4efe4; font-family: Arial, sans-serif; color: #263331; line-height: 1.6;">
<div style="max-width: 680px; margin: 0 auto; overflow: hidden; border-radius: 30px; background: #fffdf7; border: 1px solid #eadfcd; box-shadow: 0 24px 60px rgba(38, 51, 49, 0.16);">
<div style="padding: 24px 28px; background: linear-gradient(135deg, #fff8ef, #eaf7ef);">
<img src="cid:flockpal-logo" alt="FlockPal" style="display: block; width: 58px; height: 58px;" />
${
logoAttachment
? '<img src="cid:flockpal-logo" alt="FlockPal" style="display: block; width: 180px; max-width: 72%; height: auto;" />'
: '<strong style="display: block; color: #238a5a; font-size: 22px;">FlockPal</strong>'
}
</div>
<div style="padding: 30px 28px;">
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" style="border-collapse: collapse;">
+1
View File
@@ -34,6 +34,7 @@ services:
ADMIN_EMAILS: ${ADMIN_EMAILS:-}
RESCUE_STATUS_NOTIFICATION_EMAIL: ${RESCUE_STATUS_NOTIFICATION_EMAIL:-appadmin@flockpal.app}
DEFAULT_BIRD_PHOTO_PATH: ${DEFAULT_BIRD_PHOTO_PATH:-/app/assets/yoda.png}
FLOCKPAL_EMAIL_LOGO_PATH: ${FLOCKPAL_EMAIL_LOGO_PATH:-/app/assets/flockpal-logo.png}
MILESTONE_REMINDERS_ENABLED: ${MILESTONE_REMINDERS_ENABLED:-true}
MILESTONE_REMINDER_TIME_ZONE: ${MILESTONE_REMINDER_TIME_ZONE:-America/New_York}
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}
+1
View File
@@ -33,6 +33,7 @@ services:
ADMIN_EMAILS: ${ADMIN_EMAILS:-}
RESCUE_STATUS_NOTIFICATION_EMAIL: ${RESCUE_STATUS_NOTIFICATION_EMAIL:-appadmin@flockpal.app}
DEFAULT_BIRD_PHOTO_PATH: ${DEFAULT_BIRD_PHOTO_PATH:-/app/assets/yoda.png}
FLOCKPAL_EMAIL_LOGO_PATH: ${FLOCKPAL_EMAIL_LOGO_PATH:-/app/assets/flockpal-logo.png}
MILESTONE_REMINDERS_ENABLED: ${MILESTONE_REMINDERS_ENABLED:-true}
MILESTONE_REMINDER_TIME_ZONE: ${MILESTONE_REMINDER_TIME_ZONE:-America/New_York}
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}