From 83ac1eb001e43b23f1ae1f797f484c5f7262bb6e Mon Sep 17 00:00:00 2001 From: retoor Date: Sat, 8 Nov 2025 19:39:39 +0100 Subject: [PATCH] Emails. --- retoors/helpers/email_sender.py | 47 ++++++++++++ retoors/helpers/env_manager.py | 52 +++++++++++++ .../emails/password_changed_confirmation.html | 73 ++++++++++++++++++ .../emails/password_reset_request.html | 73 ++++++++++++++++++ retoors/templates/emails/welcome.html | 74 +++++++++++++++++++ retoors/templates/pages/forgot_password.html | 35 +++++++++ retoors/templates/pages/reset_password.html | 38 ++++++++++ 7 files changed, 392 insertions(+) create mode 100644 retoors/helpers/email_sender.py create mode 100644 retoors/helpers/env_manager.py create mode 100644 retoors/templates/emails/password_changed_confirmation.html create mode 100644 retoors/templates/emails/password_reset_request.html create mode 100644 retoors/templates/emails/welcome.html create mode 100644 retoors/templates/pages/forgot_password.html create mode 100644 retoors/templates/pages/reset_password.html diff --git a/retoors/helpers/email_sender.py b/retoors/helpers/email_sender.py new file mode 100644 index 0000000..69898aa --- /dev/null +++ b/retoors/helpers/email_sender.py @@ -0,0 +1,47 @@ +import aiosmtplib +from email.message import EmailMessage +from aiohttp import web +import logging + +from retoors.services.config_service import ConfigService + +logger = logging.getLogger(__name__) + +async def send_email(app: web.Application, recipient_email: str, subject: str, body: str): + """ + Sends an email asynchronously using the configured SMTP settings. + """ + config_service: ConfigService = app["config_service"] + + smtp_host = config_service.get_smtp_host() + smtp_port = config_service.get_smtp_port() + smtp_username = config_service.get_smtp_username() + smtp_password = config_service.get_smtp_password() + smtp_use_tls = config_service.get_smtp_use_tls() + smtp_sender_email = config_service.get_smtp_sender_email() + + if not smtp_host or not smtp_sender_email: + logger.error("SMTP host or sender email not configured. Cannot send email.") + return + + msg = EmailMessage() + msg["From"] = smtp_sender_email + msg["To"] = recipient_email + msg["Subject"] = subject + msg.set_content(body) + + try: + await aiosmtplib.send( + msg, + hostname=smtp_host, + port=smtp_port, + username=smtp_username, + password=smtp_password, + use_tls=False, # Always False when using start_tls + start_tls=smtp_use_tls, # Use start_tls for explicit TLS negotiation + ) + logger.info(f"Email sent successfully to {recipient_email} with subject '{subject}'") + except aiosmtplib.SMTPException as e: + logger.error(f"Failed to send email to {recipient_email}: {e}") + except Exception as e: + logger.error(f"An unexpected error occurred while sending email to {recipient_email}: {e}") diff --git a/retoors/helpers/env_manager.py b/retoors/helpers/env_manager.py new file mode 100644 index 0000000..012e0cc --- /dev/null +++ b/retoors/helpers/env_manager.py @@ -0,0 +1,52 @@ +from pathlib import Path + +def ensure_env_file_exists(env_path: Path): + """ + Ensures that a .env file exists at the specified path. + If it doesn't exist, it creates one with default values. + """ + if not env_path.exists(): + default_env_content = """# .env - Environment variables for Retoor's Cloud Solutions +# +# This file is used to configure various aspects of the application, +# including pricing, email settings, and other sensitive information. +# +# For production, it is recommended to manage these variables through +# your hosting provider's environment variable management system +# rather than committing this file to version control. + +# Pricing Configuration +# PRICE_PER_GB: Cost per gigabyte of storage. +PRICE_PER_GB=0.05 + +# SMTP (Email Sending) Configuration +# Used for sending transactional emails (e.g., welcome, password reset). +# SMTP_HOST: The hostname of your SMTP server. +# SMTP_PORT: The port of your SMTP server (e.g., 587 for TLS, 465 for SSL, 25 for unencrypted). +# SMTP_USERNAME: The username for authenticating with your SMTP server. +# SMTP_PASSWORD: The password for authenticating with your SMTP server. +# SMTP_USE_TLS: Set to True to enable STARTTLS encryption (recommended for most servers). +# SMTP_SENDER_EMAIL: The email address from which system emails will be sent. +SMTP_HOST=localhost +SMTP_PORT=1025 +SMTP_USERNAME= +SMTP_PASSWORD= +SMTP_USE_TLS=False +SMTP_SENDER_EMAIL=no-reply@retoors.com + +# IMAP (Email Receiving) Configuration (if applicable for future features) +# IMAP_HOST= +# IMAP_PORT= +# IMAP_USERNAME= +# IMAP_PASSWORD= +# IMAP_USE_SSL=True +""" + with open(env_path, "w") as f: + f.write(default_env_content) + print(f"Created default .env file at {env_path}") + else: + print(f".env file already exists at {env_path}") + +if __name__ == "__main__": + # Example usage: + ensure_env_file_exists(Path(__file__).parent.parent.parent / ".env") diff --git a/retoors/templates/emails/password_changed_confirmation.html b/retoors/templates/emails/password_changed_confirmation.html new file mode 100644 index 0000000..0c2d7e9 --- /dev/null +++ b/retoors/templates/emails/password_changed_confirmation.html @@ -0,0 +1,73 @@ + + + + + + Password Changed - Retoor's Cloud Solutions + + + +
+
+

Your Password Has Been Changed

+
+
+

Dear {{ user_name }},

+

This is a confirmation that the password for your Retoor's Cloud Solutions account has been successfully changed.

+

If you made this change, you can now log in with your new password:

+

+ Log In Now +

+

If you did not authorize this change, please contact our support team immediately.

+

Best regards,

+

The Retoor's Cloud Solutions Team

+
+ +
+ + diff --git a/retoors/templates/emails/password_reset_request.html b/retoors/templates/emails/password_reset_request.html new file mode 100644 index 0000000..36fc0fd --- /dev/null +++ b/retoors/templates/emails/password_reset_request.html @@ -0,0 +1,73 @@ + + + + + + Password Reset Request - Retoor's Cloud Solutions + + + +
+
+

Password Reset Request

+
+
+

Dear {{ user_name }},

+

We received a request to reset the password for your Retoor's Cloud Solutions account.

+

To reset your password, please click on the link below:

+

+ Reset My Password +

+

This link will expire in 1 hour. If you did not request a password reset, please ignore this email.

+

Best regards,

+

The Retoor's Cloud Solutions Team

+
+ +
+ + diff --git a/retoors/templates/emails/welcome.html b/retoors/templates/emails/welcome.html new file mode 100644 index 0000000..b9aad07 --- /dev/null +++ b/retoors/templates/emails/welcome.html @@ -0,0 +1,74 @@ + + + + + + Welcome to Retoor's Cloud Solutions! + + + +
+
+

Welcome to Retoor's Cloud Solutions!

+
+
+

Dear {{ user_name }},

+

Thank you for registering with Retoor's Cloud Solutions. We are excited to have you on board!

+

Our platform offers secure, reliable, and flexible cloud storage tailored to your needs. Whether you're a small business, a home office user, or an individual, we're here to help you manage your data with ease.

+

To get started, please log in to your dashboard:

+

+ Go to My Dashboard +

+

If you have any questions, feel free to visit our Support Page or contact our team.

+

Best regards,

+

The Retoor's Cloud Solutions Team

+
+ +
+ + diff --git a/retoors/templates/pages/forgot_password.html b/retoors/templates/pages/forgot_password.html new file mode 100644 index 0000000..7ef856e --- /dev/null +++ b/retoors/templates/pages/forgot_password.html @@ -0,0 +1,35 @@ +{% extends "layouts/base.html" %} + +{% block title %}Forgot Password - Retoor's Cloud Solutions{% endblock %} + +{% block head %} + {# Reusing form.css for styling #} +{% endblock %} + +{% block content %} +
+

Forgot Your Password?

+

Enter your email address below and we'll send you a link to reset your password.

+ +
+

Reset Password

+ {% if error %} +

{{ error }}

+ {% endif %} + {% if message %} +

{{ message }}

+ {% endif %} +
+
+ + + {% if errors.email %} +

{{ errors.email }}

+ {% endif %} +
+ +
+ +
+
+{% endblock %} diff --git a/retoors/templates/pages/reset_password.html b/retoors/templates/pages/reset_password.html new file mode 100644 index 0000000..0fa86fa --- /dev/null +++ b/retoors/templates/pages/reset_password.html @@ -0,0 +1,38 @@ +{% extends "layouts/base.html" %} + +{% block title %}Reset Password - Retoor's Cloud Solutions{% endblock %} + +{% block head %} + {# Reusing form.css for styling #} +{% endblock %} + +{% block content %} +
+

Set Your New Password

+

Please enter and confirm your new password below.

+ +
+

Reset Password

+ {% if error %} +

{{ error }}

+ {% endif %} +
+
+ + + {% if errors.password %} +

{{ errors.password }}

+ {% endif %} +
+
+ + + {% if errors.confirm_password %} +

{{ errors.confirm_password }}

+ {% endif %} +
+ +
+
+
+{% endblock %}