Emails: Add Expires header (#20285)

* Add `Expiry` header to emails, set default expiry to 30 days and allow user config via `appsettings`

* Remove `IsSmtpExpirationConfigured` as it will always have a value

* Check for `emailExpiration` value

* Removed `EmailExpiration` default value as it should be opt-in

* Simplify SMTP email expiration condition

* Fix APICompat issue

* Add implementation to `NotImplementedEmailSender`

* Rename `emailExpiration` to `expires` to match the SMTP header

* Obsolete interfaces without `expires` parameter, delegate to an existing method.

* Set expiry TimeSpan values from user configurable settings with defaults

* Fix formating

* Handle breaking changes, add obsoletion messages and simplify interfaces.

* Fix default of invite expires timespan (was being parsed as 72 days not 72 hours).

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
This commit is contained in:
Rick Butterfield
2025-10-09 13:27:53 +01:00
committed by GitHub
parent 767894b723
commit bcedc8de2a
12 changed files with 131 additions and 31 deletions

View File

@@ -68,7 +68,7 @@ public class EmailUserForgotPasswordSender : IUserForgotPasswordSender
var message = new EmailMessage(senderEmail, address.ToString(), emailSubject, emailBody, true);
await _emailSender.SendAsync(message, Constants.Web.EmailTypes.PasswordReset, true);
await _emailSender.SendAsync(message, Constants.Web.EmailTypes.PasswordReset, true, _securitySettings.PasswordResetEmailExpiry);
}
public bool CanSend() => _securitySettings.AllowPasswordReset && _emailSender.CanSendRequiredEmail();

View File

@@ -1,9 +1,11 @@
using System.Globalization;
using System.Globalization;
using System.Net;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using MimeKit;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Mail;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Email;
@@ -18,15 +20,31 @@ public class EmailUserInviteSender : IUserInviteSender
private readonly IEmailSender _emailSender;
private readonly ILocalizedTextService _localizedTextService;
private readonly GlobalSettings _globalSettings;
private readonly SecuritySettings _securitySettings;
[Obsolete("Please use the constructor with all parameters. Scheduled for removal in Umbraco 18.")]
public EmailUserInviteSender(
IEmailSender emailSender,
ILocalizedTextService localizedTextService,
IOptions<GlobalSettings> globalSettings)
: this(
emailSender,
localizedTextService,
globalSettings,
StaticServiceProvider.Instance.GetRequiredService<IOptions<SecuritySettings>>())
{
}
public EmailUserInviteSender(
IEmailSender emailSender,
ILocalizedTextService localizedTextService,
IOptions<GlobalSettings> globalSettings,
IOptions<SecuritySettings> securitySettings)
{
_emailSender = emailSender;
_localizedTextService = localizedTextService;
_globalSettings = globalSettings.Value;
_securitySettings = securitySettings.Value;
}
public async Task InviteUser(UserInvitationMessage invite)
@@ -67,7 +85,7 @@ public class EmailUserInviteSender : IUserInviteSender
var message = new EmailMessage(senderEmail, address.ToString(), emailSubject, emailBody, true);
await _emailSender.SendAsync(message, Constants.Web.EmailTypes.UserInvite, true);
await _emailSender.SendAsync(message, Constants.Web.EmailTypes.UserInvite, true, _securitySettings.UserInviteEmailExpiry);
}
public bool CanSendInvites() => _emailSender.CanSendRequiredEmail();