feat(notification): add support for public seerr logo in email (#3036)

This commit is contained in:
Felix Schneider
2026-05-18 11:21:25 +02:00
committed by GitHub
parent 08b7bd4f46
commit a8f147d083
9 changed files with 68 additions and 16 deletions

View File

@@ -16,6 +16,9 @@ import { Notification, shouldSendAdminNotification } from '..';
import type { NotificationAgent, NotificationPayload } from './agent';
import { BaseAgent } from './agent';
const PUBLIC_LOGO_URL =
'https://raw.githubusercontent.com/seerr-team/seerr/refs/heads/develop/public/logo_full.svg';
const messages = defineMessages('notifications.agents.email', {
issueType: '{type} issue',
issue: 'issue',
@@ -96,6 +99,12 @@ class EmailAgent
const settings = getSettings();
const { applicationUrl, applicationTitle } = settings.main;
const { embedPoster } = settings.notifications.agents.email;
const { usePublicLogo } = settings.notifications.agents.email.options;
const logoUrl = usePublicLogo
? PUBLIC_LOGO_URL
: applicationUrl
? `${applicationUrl}/logo_full.svg`
: undefined;
if (type === Notification.TEST_NOTIFICATION) {
return {
@@ -107,6 +116,7 @@ class EmailAgent
body: payload.message,
applicationUrl,
applicationTitle,
logoUrl,
recipientName,
recipientEmail,
},
@@ -195,6 +205,7 @@ class EmailAgent
: undefined,
applicationUrl,
applicationTitle,
logoUrl,
recipientName,
recipientEmail,
},
@@ -263,6 +274,7 @@ class EmailAgent
: undefined,
applicationUrl,
applicationTitle,
logoUrl,
recipientName,
recipientEmail,
},

View File

@@ -255,6 +255,7 @@ export interface NotificationAgentEmail extends NotificationAgentConfig {
authPass?: string;
allowSelfSigned: boolean;
senderName: string;
usePublicLogo: boolean;
pgpPrivateKey?: string;
pgpPassword?: string;
};
@@ -472,6 +473,7 @@ class Settings {
requireTls: false,
allowSelfSigned: false,
senderName: 'Seerr',
usePublicLogo: false,
},
},
discord: {

View File

@@ -19,9 +19,12 @@ div(style='display: block; background-color: #111827; padding: 2.5rem 0;')
table(style='margin: 0 auto; font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", Arial, sans-serif; color: #fff; font-size: 16px; width: 26rem;')
tr
td(style="text-align: center;")
if applicationUrl
a(href=applicationUrl style='margin: 0 1rem;')
img(src=applicationUrl +'/logo_full.png' style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
if logoUrl
if applicationUrl
a(href=applicationUrl style='margin: 0 1rem;')
img(src=logoUrl style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
else
img(src=logoUrl style='margin: 0 1rem; width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
else
div(style='margin: 0 1rem 2.5rem; font-size: 3em; font-weight: 700;')
| #{applicationTitle}

View File

@@ -19,9 +19,12 @@ div(style='display: block; background-color: #111827; padding: 2.5rem 0;')
table(style='margin: 0 auto; font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", Arial, sans-serif; color: #fff; font-size: 16px; width: 26rem;')
tr
td(style="text-align: center;")
if applicationUrl
a(href=applicationUrl style='margin: 0 1rem;')
img(src=applicationUrl +'/logo_full.png' style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
if logoUrl
if applicationUrl
a(href=applicationUrl style='margin: 0 1rem;')
img(src=logoUrl style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
else
img(src=logoUrl style='margin: 0 1rem; width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
else
div(style='margin: 0 1rem 2.5rem; font-size: 3em; font-weight: 700;')
| #{applicationTitle}

View File

@@ -19,9 +19,12 @@ div(style='display: block; background-color: #111827; padding: 2.5rem 0;')
table(style='margin: 0 auto; font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", Arial, sans-serif; color: #fff; font-size: 16px; width: 26rem;')
tr
td(style="text-align: center;")
if applicationUrl
a(href=applicationUrl style='margin: 0 1rem;')
img(src=applicationUrl +'/logo_full.png' style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
if logoUrl
if applicationUrl
a(href=applicationUrl style='margin: 0 1rem;')
img(src=logoUrl style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
else
img(src=logoUrl style='margin: 0 1rem; width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
else
div(style='margin: 0 1rem 2.5rem; font-size: 3em; font-weight: 700;')
| #{applicationTitle}

View File

@@ -19,9 +19,12 @@ div(style='display: block; background-color: #111827; padding: 2.5rem 0;')
table(style='margin: 0 auto; font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", Arial, sans-serif; color: #fff; font-size: 16px; width: 26rem;')
tr
td(style="text-align: center;")
if applicationUrl
a(href=applicationUrl style='margin: 0 1rem;')
img(src=applicationUrl +'/logo_full.png' style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
if logoUrl
if applicationUrl
a(href=applicationUrl style='margin: 0 1rem;')
img(src=logoUrl style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
else
img(src=logoUrl style='margin: 0 1rem; width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
else
div(style='margin: 0 1rem 2.5rem; font-size: 3em; font-weight: 700;')
| #{applicationTitle}
@@ -46,4 +49,4 @@ div(style='display: block; background-color: #111827; padding: 2.5rem 0;')
tr
td(style='text-align: center;')
div(style='margin: 1rem 1rem 0; font-size: 1.25em;')
| If you did not initiate this request, you may safely disregard this message.
| If you did not initiate this request, you may safely disregard this message.

View File

@@ -19,9 +19,12 @@ div(style='display: block; background-color: #111827; padding: 2.5rem 0;')
table(style='margin: 0 auto; font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", Arial, sans-serif; color: #fff; font-size: 16px; width: 26rem;')
tr
td(style="text-align: center;")
if applicationUrl
a(href=applicationUrl style='margin: 0 1rem;')
img(src=applicationUrl +'/logo_full.png' style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
if logoUrl
if applicationUrl
a(href=applicationUrl style='margin: 0 1rem;')
img(src=logoUrl style='width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
else
img(src=logoUrl style='margin: 0 1rem; width: 26rem; image-rendering: crisp-edges; image-rendering: -webkit-optimize-contrast;')
else
div(style='margin: 0 1rem 2.5rem; font-size: 3em; font-weight: 700;')
| #{applicationTitle}

View File

@@ -19,6 +19,9 @@ const messages = defineMessages('components.Settings.Notifications', {
validationSmtpPortRequired: 'You must provide a valid port number',
agentenabled: 'Enable Agent',
embedPoster: 'Embed Poster',
usePublicLogo: 'Use public Seerr logo instead of instance logo',
usePublicLogoTip:
'If your Seerr instance is not publicly accessible, enable this option so email clients outside your network can display the image. The image will be pulled from the public GitHub repository.',
userEmailRequired: 'Require user email',
emailsender: 'Sender Address',
smtpHost: 'SMTP Host',
@@ -134,6 +137,7 @@ const NotificationsEmail = () => {
initialValues={{
enabled: data.enabled,
embedPoster: data.embedPoster,
usePublicLogo: data.options.usePublicLogo,
userEmailRequired: data.options.userEmailRequired,
emailFrom: data.options.emailFrom,
smtpHost: data.options.smtpHost,
@@ -160,6 +164,7 @@ const NotificationsEmail = () => {
embedPoster: values.embedPoster,
options: {
userEmailRequired: values.userEmailRequired,
usePublicLogo: values.usePublicLogo,
emailFrom: values.emailFrom,
smtpHost: values.smtpHost,
smtpPort: Number(values.smtpPort),
@@ -209,6 +214,7 @@ const NotificationsEmail = () => {
enabled: true,
embedPoster: values.embedPoster,
options: {
usePublicLogo: values.usePublicLogo,
emailFrom: values.emailFrom,
smtpHost: values.smtpHost,
smtpPort: Number(values.smtpPort),
@@ -263,6 +269,21 @@ const NotificationsEmail = () => {
<Field type="checkbox" id="embedPoster" name="embedPoster" />
</div>
</div>
<div className="form-row">
<label htmlFor="usePublicLogo" className="checkbox-label">
{intl.formatMessage(messages.usePublicLogo)}
<span className="label-tip">
{intl.formatMessage(messages.usePublicLogoTip)}
</span>
</label>
<div className="form-input-area">
<Field
type="checkbox"
id="usePublicLogo"
name="usePublicLogo"
/>
</div>
</div>
<div className="form-row">
<label htmlFor="userEmailRequired" className="checkbox-label">
{intl.formatMessage(messages.userEmailRequired)}

View File

@@ -775,6 +775,8 @@
"components.Settings.Notifications.toastTelegramTestFailed": "Telegram test notification failed to send.",
"components.Settings.Notifications.toastTelegramTestSending": "Sending Telegram test notification…",
"components.Settings.Notifications.toastTelegramTestSuccess": "Telegram test notification sent!",
"components.Settings.Notifications.usePublicLogo": "Use public Seerr logo instead of instance logo",
"components.Settings.Notifications.usePublicLogoTip": "If your Seerr instance is not publicly accessible, enable this option so email clients outside your network can display the image. The image will be pulled from the public GitHub repository.",
"components.Settings.Notifications.useUserLocale": "Use Notification Recipient Locale",
"components.Settings.Notifications.userEmailRequired": "Require user email",
"components.Settings.Notifications.validationBotAPIRequired": "You must provide a bot authorization token",