BaseMailTemplate
Base class for the emails sent through IResendMailService, describing a message as values rather than as a Resend message object. A subclass supplies the subject, title, greeting, paragraphs, and buttons, and the base class renders both the HTML body and the plain-text alternative sent alongside it. Every value interpolated into the HTML is encoded, while the plain-text body is written as given, since it has no markup to escape.
Subject
The subject of the sent message, and the only value that is not rendered into either body. It is public because the mail service reads it while building the message, and it is abstract, so every template supplies one. PreviewAsync returns the two rendered bodies alone, so a preview never shows it.
using AlmightyShogun.Mail.Resend;
public sealed class PasswordResetMailTemplate(string url) : BaseMailTemplate
{
public override string Subject => "Reset your password";
protected override string Title => "Password reset";
protected override string Greeting => "Hello,";
protected override IReadOnlyList<string> Paragraphs =>
[
"Use the button below to choose a new password.",
"The link expires soon, request a new email if it no longer works."
];
protected override IReadOnlyList<MailButton> Buttons =>
[
new("Reset password", url)
];
}Type signature
public abstract string Subject { get; }Title
The heading of the message, substituted into the and placeholders of BaseEmailTemplate.html, so where it lands in the HTML is decided by that file. The plain-text body opens with it, followed by a blank line, unless it is blank or whitespace, in which case it is left out there entirely. It is abstract, so a template supplies one even when it has no heading to show.
Type signature
protected abstract string Title { get; }Greeting
The opening line addressing the recipient, substituted into the placeholder and written into the plain-text body after the title. It is rendered unconditionally, so a template with nothing to greet returns an empty string and leaves a blank line behind rather than being skipped the way a blank Title is.
Type signature
protected abstract string Greeting { get; }Paragraphs
The body paragraphs, in order. Each one is rendered through BaseEmailParagraph.html, with replaced by the encoded text, and repeated in the plain-text body on its own line followed by a blank line. Empty by default, which renders a message carrying only a greeting and buttons.
Type signature
protected virtual IReadOnlyList<string> Paragraphs { get; }Buttons
The call-to-action buttons rendered after the paragraphs, each through BaseEmailButton.html with and replaced, and repeated in the plain-text body as label and URL pairs so the destination survives for a client that shows only text. Empty by default. A MailButton rejects a blank or unsafe URL when it is constructed, so a bad destination throws while the list is being built rather than while the message renders.
Type signature
protected virtual IReadOnlyList<MailButton> Buttons { get; }AdditionalValues
Extra placeholder values for the template, written as in the template files. Override it to add template fields without changing the package or introducing a template engine. Empty by default, and every value is HTML encoded on the way in.
Subclass values are applied after the built-in placeholders, so a key naming one of those has no effect, apart from BodyHtml and ButtonsHtml, which are substituted last and so are overridden by a subclass key of the same name. They are applied one after another over the accumulating text, and HTML encoding leaves braces alone, so a value containing is itself substituted when that key is applied later. Enumeration order therefore decides the result.
using AlmightyShogun.Mail.Resend;
public sealed class SupportRequestMailTemplate : BaseMailTemplate
{
public override string Subject => "We received your request";
protected override string Title => "Request received";
protected override string Greeting => "Hello,";
protected override IReadOnlyDictionary<string, string> AdditionalValues
=> new Dictionary<string, string>
{
["SupportEmail"] = "support@example.com"
};
}WARNING
Additional values are applied to the HTML body only. The plain-text body has no markup to escape and no placeholders to fill, so a template that relies on an additional value for its wording renders it in the HTML alternative alone.
Type signature
protected virtual IReadOnlyDictionary<string, string> AdditionalValues { get; }