feat(email-api): wire email-api-data; load html shell templates from DB

- Add ProjectReference to email-api-data
- Register EmailApiDbContext + run migrations on startup
- Register IEmailTemplateRepository (scoped) and IEmailTemplateService (singleton)
- SmtpEmailDispatcher: inject IEmailTemplateService; replace hardcoded
  HtmlShellStart/HtmlShellEnd string constants with DB template lookups
  (email.html-shell.start / email.html-shell.end, language "*")

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-28 08:40:40 +03:00
parent 19e73aca17
commit c415ab3957
3 changed files with 34 additions and 29 deletions
+25
View File
@@ -1,5 +1,10 @@
using System.Reflection; using System.Reflection;
using EmailApi.Data;
using EmailApi.Data.Repositories;
using EmailApi.Data.Repositories.Contracts;
using EmailApi.Data.Services;
using EmailApi.Services; using EmailApi.Services;
using Microsoft.EntityFrameworkCore;
using Models.Settings; using Models.Settings;
using Serilog; using Serilog;
using StartupHelpers; using StartupHelpers;
@@ -24,6 +29,19 @@ try
builder.Services.Configure<SmtpSettings>(builder.Configuration.GetSection("Smtp")); builder.Services.Configure<SmtpSettings>(builder.Configuration.GetSection("Smtp"));
builder.Services.Configure<FileStorageSettings>(builder.Configuration.GetSection("FileStorage")); builder.Services.Configure<FileStorageSettings>(builder.Configuration.GetSection("FileStorage"));
builder.Services.AddDbContext<EmailApiDbContext>(options =>
{
var connectionString = builder.Services.GetConfiguredDbConnectionString(builder.Configuration);
options.UseSqlServer(connectionString, sql =>
{
sql.MigrationsHistoryTable(EmailApiDbContext.MigrationTableName, EmailApiDbContext.SchemaName);
sql.MigrationsAssembly("email-api-data");
});
});
builder.Services.AddScoped<IEmailTemplateRepository, EfEmailTemplateRepository>();
builder.Services.AddSingleton<IEmailTemplateService, EmailTemplateService>();
builder.Services.AddScoped<SmtpEmailDispatcher>(); builder.Services.AddScoped<SmtpEmailDispatcher>();
var app = builder.Build(); var app = builder.Build();
@@ -40,6 +58,13 @@ try
app.UseAuthorization(); app.UseAuthorization();
app.MapControllers(); app.MapControllers();
Log.Information("Running EF Core migrations if any");
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<EmailApiDbContext>();
db.Database.Migrate();
}
Log.Information("{Service} startup complete. Listening for requests...", ServiceName); Log.Information("{Service} startup complete. Listening for requests...", ServiceName);
app.Run(); app.Run();
} }
+8 -29
View File
@@ -1,3 +1,4 @@
using EmailApi.Data.Services;
using EmailApi.Models.Requests; using EmailApi.Models.Requests;
using MailKit.Net.Smtp; using MailKit.Net.Smtp;
using MailKit.Security; using MailKit.Security;
@@ -11,44 +12,19 @@ public sealed class SmtpEmailDispatcher
{ {
private readonly SmtpSettings _smtp; private readonly SmtpSettings _smtp;
private readonly FileStorageSettings _fileStorage; private readonly FileStorageSettings _fileStorage;
private readonly IEmailTemplateService _templates;
private readonly ILogger<SmtpEmailDispatcher> _log; private readonly ILogger<SmtpEmailDispatcher> _log;
private readonly string _environmentName; private readonly string _environmentName;
private static readonly string HtmlShellStart = """
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"></head>
<body style="margin:0;padding:0;background:#f4f4f4;font-family:Arial,Helvetica,sans-serif">
<table width="100%" cellpadding="0" cellspacing="0" style="padding:20px 0">
<tr><td align="center">
<table width="600" cellpadding="0" cellspacing="0"
style="background:#ffffff;border-radius:8px;max-width:600px">
<tr><td style="background:#2c5282;padding:24px 32px;border-radius:8px 8px 0 0">
<h1 style="margin:0;color:#ffffff;font-size:22px;font-weight:600">myAi</h1>
</td></tr>
<tr><td style="padding:32px">
""";
private static readonly string HtmlShellEnd = """
</td></tr>
<tr><td style="background:#f8f9fa;padding:16px 32px;text-align:center;
color:#6c757d;font-size:12px;border-radius:0 0 8px 8px">
Automated message from myAi.
</td></tr>
</table>
</td></tr>
</table>
</body>
</html>
""";
public SmtpEmailDispatcher( public SmtpEmailDispatcher(
IOptions<SmtpSettings> smtp, IOptions<SmtpSettings> smtp,
IOptions<FileStorageSettings> fileStorage, IOptions<FileStorageSettings> fileStorage,
IEmailTemplateService templates,
ILogger<SmtpEmailDispatcher> log) ILogger<SmtpEmailDispatcher> log)
{ {
_smtp = smtp.Value; _smtp = smtp.Value;
_fileStorage = fileStorage.Value; _fileStorage = fileStorage.Value;
_templates = templates;
_log = log; _log = log;
_environmentName = Environment.GetEnvironmentVariable("APP_ENVIRONMENT_NAME") ?? "Development"; _environmentName = Environment.GetEnvironmentVariable("APP_ENVIRONMENT_NAME") ?? "Development";
} }
@@ -72,9 +48,12 @@ public sealed class SmtpEmailDispatcher
msg.Subject = $"[{_environmentName}] {req.Subject}".Trim(); msg.Subject = $"[{_environmentName}] {req.Subject}".Trim();
var shellStart = _templates.Get("email.html-shell.start", "*");
var shellEnd = _templates.Get("email.html-shell.end", "*");
var builder = new BodyBuilder var builder = new BodyBuilder
{ {
HtmlBody = HtmlShellStart + req.HtmlBody + HtmlShellEnd HtmlBody = shellStart + req.HtmlBody + shellEnd
}; };
if (!string.IsNullOrWhiteSpace(req.AttachmentPath)) if (!string.IsNullOrWhiteSpace(req.AttachmentPath))
+1
View File
@@ -22,6 +22,7 @@
<ProjectReference Include="..\..\Helpers\startup-helpers\startup-helpers.csproj" /> <ProjectReference Include="..\..\Helpers\startup-helpers\startup-helpers.csproj" />
<ProjectReference Include="..\api-models\api-models.csproj" /> <ProjectReference Include="..\api-models\api-models.csproj" />
<ProjectReference Include="..\common\common.csproj" /> <ProjectReference Include="..\common\common.csproj" />
<ProjectReference Include="..\email-api-data\email-api-data.csproj" />
<ProjectReference Include="..\email-api-models\email-api-models.csproj" /> <ProjectReference Include="..\email-api-models\email-api-models.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>