feat: add configurable sender name and allow users to choose between system and personal SMTP accounts when sending emails
Build and Push Multi-Platform Images / build-and-push (push) Successful in 34s

This commit is contained in:
2026-05-06 20:49:09 +02:00
parent 8212f733ab
commit d19fd266c7
10 changed files with 72 additions and 5 deletions
@@ -23,6 +23,9 @@ export class UserSettings {
@Column({ type: 'varchar', length: 255, nullable: true })
SmtpFrom!: string | null;
@Column({ type: 'varchar', length: 255, nullable: true })
SmtpFromName!: string | null;
@Column({ type: 'text', nullable: true })
MailSignatureHtml!: string | null;
}
@@ -203,11 +203,14 @@ export class InboxController {
body: string;
html?: string;
segments: { pages: number[]; filename: string }[];
sender?: string;
},
@Request() req: any,
): Promise<void> {
const preferredUsername: string | null = req.user?.preferredUsername ?? null;
const smtpOverride = await this.userSettingsService.getSmtpConfig(req.user.userId);
const smtpOverride = body.sender === 'user'
? await this.userSettingsService.getSmtpConfig(req.user.userId)
: null;
await this.inboxService.sendAsEmail(id, preferredUsername, {
...body,
smtpOverride: smtpOverride ?? undefined,
@@ -28,7 +28,9 @@ export class MailService {
smtpOverride?: { host: string; port: number; secure: boolean; user: string; pass: string; from: string };
}): Promise<void> {
let transporter = this.transporter;
let from = this.configService.get<string>('SMTP_FROM', 'paperless@localhost');
const globalFromEmail = this.configService.get<string>('SMTP_FROM', 'paperless@localhost');
const globalFromName = this.configService.get<string>('SMTP_FROM_NAME', '');
let from = globalFromName ? `"${globalFromName}" <${globalFromEmail}>` : globalFromEmail;
if (options.smtpOverride) {
const o = options.smtpOverride;
@@ -15,6 +15,11 @@ export class UserSettingsController {
return this.userSettingsService.updateSettings(req.user.userId, body);
}
@Get('senders')
async getSenders(@Request() req: any) {
return this.userSettingsService.getAvailableSenders(req.user.userId);
}
@Post('test-smtp')
@HttpCode(200)
async testSmtp(@Body() body: { host: string; port: number; secure: boolean; user: string; pass: string }) {
@@ -15,6 +15,7 @@ export interface UserSettingsDto {
smtpUser: string | null;
smtpPassSet: boolean;
smtpFrom: string | null;
smtpFromName: string | null;
mailSignatureHtml: string | null;
}
@@ -75,6 +76,7 @@ export class UserSettingsService {
smtpUser?: string | null;
smtpPass?: string | null;
smtpFrom?: string | null;
smtpFromName?: string | null;
mailSignatureHtml?: string | null;
},
): Promise<UserSettingsDto> {
@@ -91,6 +93,7 @@ export class UserSettingsService {
entity.SmtpPass = this.encrypt(data.smtpPass);
}
if (data.smtpFrom !== undefined) entity.SmtpFrom = data.smtpFrom;
if (data.smtpFromName !== undefined) entity.SmtpFromName = data.smtpFromName;
if (data.mailSignatureHtml !== undefined) entity.MailSignatureHtml = data.mailSignatureHtml;
await this.repo.save(entity);
@@ -123,16 +126,34 @@ export class UserSettingsService {
} | null> {
const entity = await this.repo.findOne({ where: { UserId: userId } });
if (!entity?.SmtpHost || !entity?.SmtpPass) return null;
const fromEmail = entity.SmtpFrom ?? entity.SmtpUser ?? '';
const from = entity.SmtpFromName ? `"${entity.SmtpFromName}" <${fromEmail}>` : fromEmail;
return {
host: entity.SmtpHost,
port: entity.SmtpPort ?? 587,
secure: entity.SmtpSecure,
user: entity.SmtpUser ?? '',
pass: this.decrypt(entity.SmtpPass),
from: entity.SmtpFrom ?? entity.SmtpUser ?? '',
from,
};
}
async getAvailableSenders(userId: string): Promise<{ id: string; label: string }[]> {
const defaultEmail = this.configService.get<string>('SMTP_FROM', 'paperless@localhost');
const defaultName = this.configService.get<string>('SMTP_FROM_NAME', '');
const defaultLabel = defaultName ? `${defaultName} <${defaultEmail}>` : defaultEmail;
const senders: { id: string; label: string }[] = [{ id: 'default', label: defaultLabel }];
const entity = await this.repo.findOne({ where: { UserId: userId } });
if (entity?.SmtpHost && entity?.SmtpPass) {
const userEmail = entity.SmtpFrom ?? entity.SmtpUser ?? '';
const userLabel = entity.SmtpFromName ? `${entity.SmtpFromName} <${userEmail}>` : userEmail;
senders.push({ id: 'user', label: userLabel });
}
return senders;
}
private toDto(entity: UserSettings | null): UserSettingsDto {
return {
smtpHost: entity?.SmtpHost ?? null,
@@ -141,6 +162,7 @@ export class UserSettingsService {
smtpUser: entity?.SmtpUser ?? null,
smtpPassSet: !!(entity?.SmtpPass),
smtpFrom: entity?.SmtpFrom ?? null,
smtpFromName: entity?.SmtpFromName ?? null,
mailSignatureHtml: entity?.MailSignatureHtml ?? null,
};
}