Since lesson 2.8.4, every booking writes a confirmation into the outbox, and the sender works through it, so far only into the log. In this lesson, that becomes a real mail with a link. Only whoever opens the link and confirms there has really booked the appointment. That way the office knows that the given address is right and that the person wants the appointment, and a stranger can't push an appointment on anyone.
Mail as a port
How the Kladde sends mail should live in one place and be replaceable. In development, no mail should reach a real mailbox; in production, it
should go through Microsoft 365; in a test, nobody should send it. That's the case for a port like IKladdeStore or ITenderSource:
// src/Kladde.Core/Mail/IMailSender.cs
using Kladde.Core.Outbox;
namespace Kladde.Core.Mail;
/// <summary>A mail as the Kladde sends it: plain text to one recipient, with the id of the outbox message it belongs to.</summary>
public sealed record OutgoingMail(Guid Id, string To, string Subject, string Text);
/// <summary>Sends mails. Says whether a mail went out, certainly did not, or nobody knows.</summary>
public interface IMailSender
{
Task<DeliveryOutcome> SendAsync(OutgoingMail mail, CancellationToken cancellationToken);
}
SendAsync returns the same DeliveryOutcome as a delivery of the outbox: delivered, certainly not delivered, or unclear. The distinction from
lesson 2.8.3 thus travels from the mail all the way into the outbox's table. The mail carries the id of its message in the outbox; whoever gets the
same id twice knows that it's the same mail.