mirror of
https://github.com/immich-app/immich
synced 2025-10-17 18:19:27 +00:00
* feat(server): Option to configure SMTPS transport This commit adds a boolean option in the SMTP transport configuration to enable the so-called "secure" mode. What it does is use SMTP over TLS instead of relying on the more common STARTTLS option over plain SMTP. * Add missing field in dto * Add missing field * Use a switch instead of text field * Add field in spec * chore: regen open-api --------- Co-authored-by: Jason Rasmussen <jason@rasm.me>
112 lines
4.2 KiB
TypeScript
112 lines
4.2 KiB
TypeScript
import { defaults, SystemConfig } from 'src/config';
|
|
import { EmailTemplate } from 'src/repositories/email.repository';
|
|
import { NotificationService } from 'src/services/notification.service';
|
|
import { userStub } from 'test/fixtures/user.stub';
|
|
import { newTestService, ServiceMocks } from 'test/utils';
|
|
|
|
const smtpTransport = Object.freeze<SystemConfig>({
|
|
...defaults,
|
|
notifications: {
|
|
smtp: {
|
|
...defaults.notifications.smtp,
|
|
enabled: true,
|
|
transport: {
|
|
ignoreCert: false,
|
|
host: 'localhost',
|
|
port: 587,
|
|
secure: false,
|
|
username: 'test',
|
|
password: 'test',
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
describe(NotificationService.name, () => {
|
|
let sut: NotificationService;
|
|
let mocks: ServiceMocks;
|
|
|
|
beforeEach(() => {
|
|
({ sut, mocks } = newTestService(NotificationService));
|
|
});
|
|
|
|
it('should work', () => {
|
|
expect(sut).toBeDefined();
|
|
});
|
|
|
|
describe('sendTestEmail', () => {
|
|
it('should throw error if user could not be found', async () => {
|
|
await expect(sut.sendTestEmail('', smtpTransport.notifications.smtp)).rejects.toThrow('User not found');
|
|
});
|
|
|
|
it('should throw error if smtp validation fails', async () => {
|
|
mocks.user.get.mockResolvedValue(userStub.admin);
|
|
mocks.email.verifySmtp.mockRejectedValue('');
|
|
|
|
await expect(sut.sendTestEmail('', smtpTransport.notifications.smtp)).rejects.toThrow(
|
|
'Failed to verify SMTP configuration',
|
|
);
|
|
});
|
|
|
|
it('should send email to default domain', async () => {
|
|
mocks.user.get.mockResolvedValue(userStub.admin);
|
|
mocks.email.verifySmtp.mockResolvedValue(true);
|
|
mocks.email.renderEmail.mockResolvedValue({ html: '', text: '' });
|
|
mocks.email.sendEmail.mockResolvedValue({ messageId: 'message-1', response: '' });
|
|
|
|
await expect(sut.sendTestEmail('', smtpTransport.notifications.smtp)).resolves.not.toThrow();
|
|
expect(mocks.email.renderEmail).toHaveBeenCalledWith({
|
|
template: EmailTemplate.TEST_EMAIL,
|
|
data: { baseUrl: 'https://my.immich.app', displayName: userStub.admin.name },
|
|
});
|
|
expect(mocks.email.sendEmail).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
subject: 'Test email from Immich',
|
|
smtp: smtpTransport.notifications.smtp.transport,
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('should send email to external domain', async () => {
|
|
mocks.user.get.mockResolvedValue(userStub.admin);
|
|
mocks.email.verifySmtp.mockResolvedValue(true);
|
|
mocks.email.renderEmail.mockResolvedValue({ html: '', text: '' });
|
|
mocks.systemMetadata.get.mockResolvedValue({ server: { externalDomain: 'https://demo.immich.app' } });
|
|
mocks.email.sendEmail.mockResolvedValue({ messageId: 'message-1', response: '' });
|
|
|
|
await expect(sut.sendTestEmail('', smtpTransport.notifications.smtp)).resolves.not.toThrow();
|
|
expect(mocks.email.renderEmail).toHaveBeenCalledWith({
|
|
template: EmailTemplate.TEST_EMAIL,
|
|
data: { baseUrl: 'https://demo.immich.app', displayName: userStub.admin.name },
|
|
});
|
|
expect(mocks.email.sendEmail).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
subject: 'Test email from Immich',
|
|
smtp: smtpTransport.notifications.smtp.transport,
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('should send email with replyTo', async () => {
|
|
mocks.user.get.mockResolvedValue(userStub.admin);
|
|
mocks.email.verifySmtp.mockResolvedValue(true);
|
|
mocks.email.renderEmail.mockResolvedValue({ html: '', text: '' });
|
|
mocks.email.sendEmail.mockResolvedValue({ messageId: 'message-1', response: '' });
|
|
|
|
await expect(
|
|
sut.sendTestEmail('', { ...smtpTransport.notifications.smtp, replyTo: 'demo@immich.app' }),
|
|
).resolves.not.toThrow();
|
|
expect(mocks.email.renderEmail).toHaveBeenCalledWith({
|
|
template: EmailTemplate.TEST_EMAIL,
|
|
data: { baseUrl: 'https://my.immich.app', displayName: userStub.admin.name },
|
|
});
|
|
expect(mocks.email.sendEmail).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
subject: 'Test email from Immich',
|
|
smtp: smtpTransport.notifications.smtp.transport,
|
|
replyTo: 'demo@immich.app',
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
});
|