diff --git a/.env-example b/.env-example new file mode 100644 index 0000000..f772cea --- /dev/null +++ b/.env-example @@ -0,0 +1,31 @@ +APP_MODULE=src.main:app +APP_HOST=0.0.0.0 +APP_PORT=8000 +APP_WORKERS=3 + +VAULT_ADDR=http://localhost:8200 +VAULT_ROLE_ID=replace-me +VAULT_SECRET_ID=replace-me +VAULT_AUTH_MOUNT=approle +VAULT_MOUNT_POINT=secrets + +DOCS_USERNAME=admin +DOCS_PASSWORD=admin + +RABBIT_HOST=localhost +RABBIT_PORT=5672 +RABBIT_USER=guest +RABBIT_PASSWORD=guest +RABBIT_VHOST=/ +RABBIT_PUBLISH_PERSIST=true +RABBIT_CONNECT_TIMEOUT=5 +RABBIT_EMAIL_CODE_QUEUE=email.verification_code + +SMTP_FROM= +SMTP_HOST=localhost +SMTP_PORT=587 +SMTP_USER= +SMTP_PASSWORD= + +LOG_LEVEL=INFO +LOG_FORMAT=TEXT diff --git a/src/infrastructure/mail/assets.py b/src/infrastructure/mail/assets.py new file mode 100644 index 0000000..59c8853 --- /dev/null +++ b/src/infrastructure/mail/assets.py @@ -0,0 +1,11 @@ +import base64 +from pathlib import Path + +_LOGO_PATH = Path(__file__).resolve().parent / 'templates' / 'static' / 'exa-logo.png' + + +def get_exa_logo_data_uri() -> str | None: + if not _LOGO_PATH.is_file(): + return None + data = base64.b64encode(_LOGO_PATH.read_bytes()).decode('ascii') + return f'data:image/png;base64,{data}' diff --git a/src/infrastructure/mail/templates/email_code.html b/src/infrastructure/mail/templates/email_code.html index 6747230..e4e48e6 100644 --- a/src/infrastructure/mail/templates/email_code.html +++ b/src/infrastructure/mail/templates/email_code.html @@ -3,52 +3,43 @@ - + {{ subject }} - + -
Ваш код: {{ code }}. Действует {{ ttl_minutes }} мин.  ͏
+ style="background:#F2F1E8;padding:32px 16px;">
- + style="max-width:600px;width:100%;border-radius:12px;overflow:hidden; + box-shadow:0 4px 24px rgba(14,16,61,0.08);border:1px solid rgba(14,16,61,0.08);"> - -
+ - - @@ -56,57 +47,42 @@ - -
-
+
+ {% if logo_data_uri %} + {{ brand }} + {% else %} +
{{ brand }}
-
- Подтверждение · Безопасность -
-
- -
- 🔐 + {% endif %} +
+ Подтверждение действия
+ - -
+
Ваш код подтверждения
-
- Введите этот код в приложении, чтобы завершить действие. - Никому не сообщайте его. +
+ Введите код в приложении {{ brand }}. Не пересылайте это письмо и не сообщайте код другим людям.
- + style="margin-top:22px;"> -
+ -
+
код подтверждения
-
+
{{ code }}
- + style="margin:16px auto 0;"> - @@ -116,17 +92,13 @@
- - ⏱ Действует {{ ttl_minutes }} мин + + + Действует {{ ttl_minutes }} мин
- + style="margin-top:18px;"> - @@ -135,25 +107,15 @@ - - - - - - -
-
- ⚠️ Если вы не запрашивали код — просто проигнорируйте - это письмо. Никогда не сообщайте код третьим лицам. +
+
+ Если вы не запрашивали код, проигнорируйте письмо. Служба поддержки {{ brand }} никогда не попросит код по телефону или в мессенджере.
-
-
-
+ -
- © {{ year }} {{ brand }}
- Ref: {{ trace_id }} +
+ © {{ year }} {{ brand }}
+ Ref: {{ trace_id }}
@@ -161,11 +123,10 @@
-
- \ No newline at end of file + diff --git a/src/infrastructure/mail/templates/email_code.txt b/src/infrastructure/mail/templates/email_code.txt index 46cfdfb..94be5ee 100644 --- a/src/infrastructure/mail/templates/email_code.txt +++ b/src/infrastructure/mail/templates/email_code.txt @@ -1,7 +1,10 @@ {{ brand }} -Ваш код подтверждения: {{ code }} +Код подтверждения: {{ code }} Срок действия: {{ ttl_minutes }} минут -Если вы не запрашивали код — игнорируйте это письмо. +Введите код в приложении {{ brand }}. Не сообщайте код третьим лицам. -Ref: {{ trace_id }} \ No newline at end of file +Если вы не запрашивали код — проигнорируйте это письмо. + +© {{ year }} {{ brand }} +Ref: {{ trace_id }} diff --git a/src/infrastructure/mail/templates/static/exa-logo.png b/src/infrastructure/mail/templates/static/exa-logo.png new file mode 100644 index 0000000..f59a52c Binary files /dev/null and b/src/infrastructure/mail/templates/static/exa-logo.png differ diff --git a/src/presentation/messaging/code.py b/src/presentation/messaging/code.py index 8cef13c..a9c4495 100644 --- a/src/presentation/messaging/code.py +++ b/src/presentation/messaging/code.py @@ -3,6 +3,7 @@ from faststream.rabbit.fastapi import RabbitRouter, RabbitMessage from src.infrastructure.config import settings from src.infrastructure.logger import logger from src.infrastructure.mail import TemplateRenderer, get_email_sender, get_renderer +from src.infrastructure.mail.assets import get_exa_logo_data_uri from src.infrastructure.mail.sender import EmailSender from datetime import datetime from typing import Literal, Optional @@ -52,27 +53,31 @@ async def consume_email_code( f"trace_id={trace_id}" ) + logo_data_uri = get_exa_logo_data_uri() + html = renderer.render( - "email_code.html", - subject="Код подтверждения", + 'email_code.html', + subject='Экса — код подтверждения', code=msg_body.payload.code, ttl_minutes=msg_body.payload.ttl_seconds // 60, - brand="Bitforce", + brand='Экса', + logo_data_uri=logo_data_uri, trace_id=trace_id, year=datetime.now().year, ) text = renderer.render( - "email_code.txt", + 'email_code.txt', code=msg_body.payload.code, ttl_minutes=msg_body.payload.ttl_seconds // 60, - brand="Bitforce", + brand='Экса', trace_id=trace_id, + year=datetime.now().year, ) await sender.send( to=msg_body.payload.email, - subject="Код подтверждения", + subject='Экса — код подтверждения', body=html, plain=text, ) \ No newline at end of file