Files
btcpayserver/BTCPayServer/Plugins/Emails/EmailsPlugin.cs
2025-11-10 17:24:27 +09:00

147 lines
6.9 KiB
C#

using System.Collections.Generic;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Data;
using BTCPayServer.Plugins.Emails.HostedServices;
using BTCPayServer.Plugins.Emails.Views;
using BTCPayServer.Plugins.Webhooks;
using BTCPayServer.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace BTCPayServer.Plugins.Emails;
public class EmailsPlugin : BaseBTCPayServerPlugin
{
public const string Area = "Emails";
public override string Identifier => "BTCPayServer.Plugins.Emails";
public override string Name => "Emails";
public override string Description => "Allows you to send emails to your customers!";
public override void Execute(IServiceCollection services)
{
services.AddSingleton<IDefaultTranslationProvider, EmailsTranslationProvider>();
services.AddSingleton<IHostedService, StoreEmailRuleProcessorSender>();
services.AddSingleton<IHostedService, UserEventHostedService>();
services.AddMigration<ApplicationDbContext, DefaultServerEmailRulesMigration>();
RegisterServerEmailTriggers(services);
}
private static string BODY_STYLE = "font-family: Open Sans, Helvetica Neue,Arial,sans-serif; font-color: #292929;";
private static string HEADER_HTML = "<h1 style='font-size:1.2rem'>{Branding.ServerName}</h1><br/>";
private static string BUTTON_HTML = "<a href='{button_link}' type='submit' style='min-width: 2em;min-height: 20px;text-decoration-line: none;cursor: pointer;display: inline-block;font-weight: 400;color: #fff;text-align: center;vertical-align: middle;user-select: none;background-color: #51b13e;border-color: #51b13e;border: 1px solid transparent;padding: 0.375rem 0.75rem;font-size: 1rem;line-height: 1.5;border-radius: 0.25rem;transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;'>{button_description}</a>";
private static string CallToAction(string actionName, string actionLink)
{
var button = $"{BUTTON_HTML}".Replace("{button_description}", actionName, System.StringComparison.InvariantCulture);
return button.Replace("{button_link}", actionLink, System.StringComparison.InvariantCulture);
}
private static string CreateEmailBody(string body) => $"<html><body style='{BODY_STYLE}'>{HEADER_HTML}{body}</body></html>";
private void RegisterServerEmailTriggers(IServiceCollection services)
{
List<EmailTriggerViewModel> vms = new();
var vm = new EmailTriggerViewModel()
{
Trigger = ServerMailTriggers.PasswordReset,
DefaultEmail = new()
{
To = ["{User.MailboxAddress}"],
Subject = "Update Password",
Body = CreateEmailBody($"A request has been made to reset your {{Branding.ServerName}} password. Please set your password by clicking below.<br/><br/>{CallToAction("Update Password", "{ResetLink}")}"),
},
PlaceHolders = new()
{
new ("{ResetLink}", "The link to the password reset page")
},
Description = "User: Password Reset Requested",
};
vms.Add(vm);
vm = new EmailTriggerViewModel()
{
Trigger = ServerMailTriggers.EmailConfirm,
DefaultEmail = new()
{
To = ["{User.MailboxAddress}"],
Subject = "Confirm your email address",
Body = CreateEmailBody($"Please confirm your account.<br/><br/>{CallToAction("Confirm Email", "{ConfirmLink}")}"),
},
PlaceHolders = new()
{
new ("{ConfirmLink}", "The link used to confirm the user's email address")
},
Description = "User: Email confirmation",
};
vms.Add(vm);
vm = new EmailTriggerViewModel()
{
Trigger = ServerMailTriggers.InvitePending,
DefaultEmail = new()
{
To = ["{User.MailboxAddress}"],
Subject = "Invitation to join {Branding.ServerName}",
Body = CreateEmailBody($"<p>Please complete your account setup by clicking <a href='{{InvitationLink}}'>this link</a>.</p><p>You can also use the BTCPay Server app and scan this QR code when connecting:</p>{{InvitationLinkQR}}"),
},
PlaceHolders = new()
{
new ("{InvitationLink}", "The link where the invited user can set up their account"),
new ("{InvitationLinkQR}", "The QR code representation of the invitation link")
},
Description = "User: Invitation",
};
vms.Add(vm);
vm = new EmailTriggerViewModel()
{
Trigger = ServerMailTriggers.ApprovalConfirmed,
DefaultEmail = new()
{
To = ["{User.MailboxAddress}"],
Subject = "Your account has been approved",
Body = CreateEmailBody($"Your account has been approved and you can now.<br/><br/>{CallToAction("Login here", "{LoginLink}")}"),
},
PlaceHolders = new()
{
new ("{LoginLink}", "The link that the user can use to login"),
},
Description = "User: Account approved",
};
vms.Add(vm);
vm = new EmailTriggerViewModel()
{
Trigger = ServerMailTriggers.ApprovalRequest,
DefaultEmail = new()
{
To = ["{Admin.MailboxAddresses}"],
Subject = "Approval request to access the server for {User.Email}",
Body = CreateEmailBody($"A new user ({{User.MailboxAddress}}), is awaiting approval to access the server.<br/><br/>{CallToAction("Approve", "{ApprovalLink}")}"),
},
PlaceHolders = new()
{
new ("{ApprovalLink}", "The link that the admin needs to use to approve the user"),
},
Description = "Admin: Approval request",
};
vms.Add(vm);
var commonPlaceholders = new List<EmailTriggerViewModel.PlaceHolder>()
{
new("{Admins.MailboxAddresses}", "The email addresses of the admins separated by a comma"),
new("{User.Name}", "The name of the user (eg. John Doe)"),
new("{User.Email}", "The email of the user (eg. john.doe@example.com)"),
new("{User.MailboxAddress}", "The formatted mailbox address to use when sending an email. (eg. \"John Doe\" <john.doe@example.com>)"),
new("{Branding.ServerName}", "The name of the server (You can configure this in Server Settings ➡ Branding)"),
new("{Branding.ContactUrl}", "The contact URL of the server (You can configure this in Server Settings ➡ Branding)"),
};
foreach (var v in vms)
{
v.ServerTrigger = true;
v.PlaceHolders.InsertRange(0, commonPlaceholders);
services.AddSingleton(v);
}
}
}