feat: add email-api service and email-api-models contract project

New internal service that centralises SMTP email sending.
- email-api-models: SendEmailRequest DTO, IEmailApiClient Refit interface, EmailApiSettings
- email-api: SmtpEmailDispatcher (MailKit), EmailController (POST /api/email/send),
  branded HTML shell wrapper, shared-Files-volume attachment support
- Protected by X-Internal-Api-Key via UseInternalApiKeyProtection()
- No exposed Docker port — internal network only (http://email-api:8080)

Closes #22

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-27 16:15:59 +03:00
parent 45d991ab5b
commit 26b13f6dbf
10 changed files with 326 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
# email-api — Internal Email Sending Service
Internal only. Reachable at `http://email-api:8080` within `myai-network`. Not exposed to the internet.
## Responsibilities
- Accepts `POST /api/email/send` requests from internal services (`api`, `cv-search-job`)
- Wraps the provided HTML body fragment in a branded HTML shell (blue header, white card, grey footer)
- Sends the email via SMTP using MailKit
- Attaches files from the shared `Files` volume when `AttachmentPath` is provided
- Protected by `X-Internal-Api-Key` via `UseInternalApiKeyProtection()`
## Key route
| Method | Route | Description |
|--------|-------|-------------|
| POST | `/api/email/send` | Send an HTML email. Returns 204 No Content. |
## Request body (`SendEmailRequest`)
| Field | Required | Notes |
|-------|----------|-------|
| `To` | ✅ | List of recipient addresses |
| `ReplyTo` | ❌ | Optional reply-to address |
| `Subject` | ✅ | Plain text (service prepends `[ENV_NAME]`) |
| `HtmlBody` | ✅ | HTML fragment — wrapped in branded shell by this service |
| `AttachmentPath` | ❌ | Path relative to `FileStorage:Path`, e.g. `"{cvDocumentId}.pdf"` |
## Consumers
- `api` — via `IEmailApiClient` Refit interface (contact, subscribe, file-download, match emails)
- `cv-search-job` — via `IEmailApiClient` Refit interface (job search results email)
## Settings
| Section | Env var | Notes |
|---------|---------|-------|
| `Smtp` | `Smtp__Host`, `Smtp__Username`, `Smtp__Password`, etc. | SMTP server config — only configured here, not in consumers |
| `FileStorage` | `FileStorage__Path` | Must match the shared `Files` volume mount path |
| `InternalApi` | `EmailApi__InternalApiKey` | API key enforced on every request |