Skip to content

Dependencies: Update MailKit dependency and resolve nullability breaking changes (for Umbraco 13) - #23306

Merged
AndyButland merged 3 commits into
release/13.16.0from
v13/task/update-mailkit-dependency
Jul 8, 2026
Merged

Dependencies: Update MailKit dependency and resolve nullability breaking changes (for Umbraco 13)#23306
AndyButland merged 3 commits into
release/13.16.0from
v13/task/update-mailkit-dependency

Conversation

@AndyButland

@AndyButland AndyButland commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Description

Updates the MailKit dependency from 4.8.0 → 4.17.0 to remediate a known vulnerability in the previously referenced version. Although this is a minor version bump, it surfaced nullability-related compiler breaking changes, which are resolved here.

Why a minor bump broke the build

This is not a runtime API change. Between 4.8.0 and 4.16.0, MailKit/MimeKit enabled <Nullable>enable</Nullable> in their own build, so the shipped assemblies now carry nullable reference type annotations. 4.8.0 was nullable-oblivious (consumers got no warnings); 4.17.0 exposes real nullability, producing warnings — errors, under warnings-as-errors — at our call sites. Every change below is resolving a newly surfaced annotation, not a behavioural change in the library.

Changes

  • Directory.Packages.props — MailKit 4.8.04.17.0.
  • EmailMessageExtensions.cs
    • InternetAddress.TryParse now declares [NotNullWhen(true)] out InternetAddress?, so the out locals become InternetAddress? (the [NotNullWhen(true)] keeps their use inside the success branch warning-free).
    • MimeMessage.Subject and TextPart.Text require non-null values. Since EmailMessage's constructor already enforces a non-null/non-empty Subject and Body, these use the null-forgiving operator (mailMessage.Subject! / mailMessage.Body!) to make that invariant explicit. This keeps the original runtime behaviour and avoids masking an invalid EmailMessage — coalescing to string.Empty would silently hide such a violation.
    • Simplified the notification display name to mailboxAddress.Name ?? string.Empty (dropped a redundant null-conditional on an already-proven-non-null value; InternetAddress.Name is genuinely nullable, so the empty default is warranted here).
  • EmailSender.csSmtpClient.ConnectAsync(host, …) requires a non-null host. Rather than silently pass an empty string (Host is required config, and empty is never valid), added a guard that throws a clear InvalidOperationException when no SMTP host is configured.
  • UsersController.csMailboxAddress(string? name, string address) requires a non-null address. An invite email cannot be sent without a recipient, so rather than defaulting to string.Empty this now fails fast with a clear InvalidOperationException when the recipient has no email address.

Testing

To verify the full send path end-to-end I used this throwaway debug controller you can drop into src/Umbraco.Web.UI/Controllers/.

Log in, configure SMTP (e.g. using smtp4dev or a SpecifiedPickupDirectory to write .eml files to disk without a real server), then hit /umbraco/surface/debugemail/send?to=you@example.com.

using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.Mail;
using Umbraco.Cms.Core.Models.Email;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Web.Website.Controllers;

namespace Umbraco.Cms.Web.UI.Controllers;

public class DebugEmailController : SurfaceController
{
    private readonly IEmailSender _emailSender;

    public DebugEmailController(
        IUmbracoContextAccessor umbracoContextAccessor,
        IUmbracoDatabaseFactory databaseFactory,
        ServiceContext services,
        AppCaches appCaches,
        IProfilingLogger profilingLogger,
        IPublishedUrlProvider publishedUrlProvider,
        IEmailSender emailSender)
        : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider)
        => _emailSender = emailSender;

    [HttpGet]
    public async Task<IActionResult> Send(string to = "recipient@example.com", string? from = null, bool html = false)
    {
        if (!_emailSender.CanSendRequiredEmail())
        {
            return StatusCode(
                StatusCodes.Status500InternalServerError,
                "Email is not configured: neither an SMTP server nor a pickup directory is set up.");
        }

        var message = new EmailMessage(
            from,
            to,
            "Umbraco MailKit upgrade test",
            html
                ? "<p>This is a <strong>test</strong> email sent from the debug controller.</p>"
                : "This is a test email sent from the debug controller.",
            html);

        try
        {
            await _emailSender.SendAsync(message, "Debug");
        }
        catch (Exception ex)
        {
            return StatusCode(StatusCodes.Status500InternalServerError, $"Failed to send email to '{to}':\n\n{ex}");
        }

        return Ok($"Email to '{to}' was handed off to the sender without error.");
    }
}

⚠️ Security note This snippet is deliberately unhardened for local convenience. It's included here purely as a testing aid.

Copilot AI review requested due to automatic review settings July 7, 2026 09:43
@AndyButland AndyButland changed the title Update MailKit dependency and resolve nullability breaking changes Dependencies: Update MailKit dependency and resolve nullability breaking changes (for Umbraco 13) Jul 7, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request upgrades the MailKit dependency to remediate a vulnerability and updates Umbraco’s email-related call sites to compile cleanly against MailKit/MimeKit assemblies that now ship with nullable reference type annotations.

Changes:

  • Bumped MailKit package version from 4.8.0 to 4.17.0.
  • Updated MIME/message construction to satisfy new nullability annotations (e.g., InternetAddress.TryParse out vars; MimeMessage.Subject / TextPart.Text assignments).
  • Added an SMTP host guard in EmailSender to fail earlier with a clearer configuration error.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
Directory.Packages.props Updates MailKit package version to 4.17.0.
src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs Adjusts parsing and MIME message creation to align with new nullable annotations.
src/Umbraco.Infrastructure/Mail/EmailSender.cs Adds configuration guard before SMTP connection.
src/Umbraco.Web.BackOffice/Controllers/UsersController.cs Updates invite-email recipient mailbox construction for new nullability requirements.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Umbraco.Web.BackOffice/Controllers/UsersController.cs Outdated
Comment thread src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs Outdated
Comment thread src/Umbraco.Infrastructure/Extensions/EmailMessageExtensions.cs Outdated
Comment thread src/Umbraco.Infrastructure/Mail/EmailSender.cs

@Zeegaan Zeegaan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, tests good 😁
I am a little concerned with packages compiled against earlier versions, but it should theoretically be fine if its just nullability right 🤔

@AndyButland

Copy link
Copy Markdown
Contributor Author

I think so - as you say, the changes are only related to nullability. It's also quite unlikely that anyone would take a direct reference to this, given we have an email sending abstraction in core. We'll put this out as an RC with the usual two weeks too.

@AndyButland
AndyButland merged commit 829cae7 into release/13.16.0 Jul 8, 2026
17 of 18 checks passed
@AndyButland
AndyButland deleted the v13/task/update-mailkit-dependency branch July 8, 2026 04:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants