feat: integrate Resend HTTP API support for firewall-safe email delivery
Browse files
backend/app/config/settings.py
CHANGED
|
@@ -34,6 +34,7 @@ class Settings(BaseSettings):
|
|
| 34 |
SMTP_PORT: int = Field(default=587)
|
| 35 |
SMTP_USER: str = Field(default="")
|
| 36 |
SMTP_PASSWORD: str = Field(default="")
|
|
|
|
| 37 |
SMTP_FROM: str = Field(default="noreply@quantiq.io")
|
| 38 |
DEVELOPER_EMAIL: str = Field(default="karanshelar8775@gmail.com")
|
| 39 |
|
|
|
|
| 34 |
SMTP_PORT: int = Field(default=587)
|
| 35 |
SMTP_USER: str = Field(default="")
|
| 36 |
SMTP_PASSWORD: str = Field(default="")
|
| 37 |
+
RESEND_API_KEY: str = Field(default="")
|
| 38 |
SMTP_FROM: str = Field(default="noreply@quantiq.io")
|
| 39 |
DEVELOPER_EMAIL: str = Field(default="karanshelar8775@gmail.com")
|
| 40 |
|
backend/app/services/email_service.py
CHANGED
|
@@ -7,6 +7,41 @@ from backend.app.config.settings import settings
|
|
| 7 |
|
| 8 |
logger = logging.getLogger("quantiq.email")
|
| 9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
def send_price_alert_email(to_email: str, ticker: str, condition: str, target_price: float, current_price: float) -> bool:
|
| 11 |
"""
|
| 12 |
Sends a price alert notification email using SMTP config, or logs to console as a fallback.
|
|
@@ -80,6 +115,10 @@ def send_price_alert_email(to_email: str, ticker: str, condition: str, target_pr
|
|
| 80 |
f"{text_content}\n"
|
| 81 |
f"========================================")
|
| 82 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
# Check if SMTP configuration is available
|
| 84 |
if not settings.SMTP_HOST or not settings.SMTP_USER or not settings.SMTP_PASSWORD:
|
| 85 |
logger.warning("SMTP settings not configured. E-mail simulated via logs above.")
|
|
@@ -168,6 +207,10 @@ def send_verification_email(to_email: str, code: str, raise_on_error: bool = Fal
|
|
| 168 |
f"{text_content}\n"
|
| 169 |
f"========================================")
|
| 170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
# Check if SMTP configuration is available
|
| 172 |
if not settings.SMTP_HOST or not settings.SMTP_USER or not settings.SMTP_PASSWORD:
|
| 173 |
logger.warning("SMTP settings not configured. Verification e-mail simulated via logs above.")
|
|
|
|
| 7 |
|
| 8 |
logger = logging.getLogger("quantiq.email")
|
| 9 |
|
| 10 |
+
def send_email_via_resend(to_email: str, subject: str, text_content: str, html_content: str, raise_on_error: bool = False) -> bool:
|
| 11 |
+
"""
|
| 12 |
+
Sends an email using the Resend HTTP API.
|
| 13 |
+
"""
|
| 14 |
+
import httpx
|
| 15 |
+
|
| 16 |
+
headers = {
|
| 17 |
+
"Authorization": f"Bearer {settings.RESEND_API_KEY}",
|
| 18 |
+
"Content-Type": "application/json"
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
payload = {
|
| 22 |
+
"from": settings.SMTP_FROM,
|
| 23 |
+
"to": [to_email],
|
| 24 |
+
"subject": subject,
|
| 25 |
+
"html": html_content,
|
| 26 |
+
"text": text_content
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
try:
|
| 30 |
+
response = httpx.post("https://api.resend.com/emails", json=payload, headers=headers, timeout=10.0)
|
| 31 |
+
if response.status_code in (200, 201):
|
| 32 |
+
logger.info(f"Successfully sent email to {to_email} via Resend API")
|
| 33 |
+
return True
|
| 34 |
+
|
| 35 |
+
logger.error(f"Resend API returned error status {response.status_code}: {response.text}")
|
| 36 |
+
if raise_on_error:
|
| 37 |
+
raise Exception(f"Resend API error (status {response.status_code}): {response.text}")
|
| 38 |
+
return False
|
| 39 |
+
except Exception as e:
|
| 40 |
+
logger.error(f"Failed to connect to Resend API: {e}")
|
| 41 |
+
if raise_on_error:
|
| 42 |
+
raise e
|
| 43 |
+
return False
|
| 44 |
+
|
| 45 |
def send_price_alert_email(to_email: str, ticker: str, condition: str, target_price: float, current_price: float) -> bool:
|
| 46 |
"""
|
| 47 |
Sends a price alert notification email using SMTP config, or logs to console as a fallback.
|
|
|
|
| 115 |
f"{text_content}\n"
|
| 116 |
f"========================================")
|
| 117 |
|
| 118 |
+
# Check if Resend HTTP API should be used
|
| 119 |
+
if settings.RESEND_API_KEY:
|
| 120 |
+
return send_email_via_resend(to_email, subject, text_content, html_content)
|
| 121 |
+
|
| 122 |
# Check if SMTP configuration is available
|
| 123 |
if not settings.SMTP_HOST or not settings.SMTP_USER or not settings.SMTP_PASSWORD:
|
| 124 |
logger.warning("SMTP settings not configured. E-mail simulated via logs above.")
|
|
|
|
| 207 |
f"{text_content}\n"
|
| 208 |
f"========================================")
|
| 209 |
|
| 210 |
+
# Check if Resend HTTP API should be used
|
| 211 |
+
if settings.RESEND_API_KEY:
|
| 212 |
+
return send_email_via_resend(to_email, subject, text_content, html_content, raise_on_error=raise_on_error)
|
| 213 |
+
|
| 214 |
# Check if SMTP configuration is available
|
| 215 |
if not settings.SMTP_HOST or not settings.SMTP_USER or not settings.SMTP_PASSWORD:
|
| 216 |
logger.warning("SMTP settings not configured. Verification e-mail simulated via logs above.")
|