SentinelScan-WSS / backend /utils /email_service.py
larxius's picture
Deploy SentinelScan WSS to HF Spaces
d543fc1 verified
Raw
History Blame Contribute Delete
6.03 kB
import os
import resend
from datetime import datetime
import threading
# Fallback to the environment variable or use the hardcoded one we verified
RESEND_API_KEY = os.getenv('RESEND_API_KEY', 're_KB1gXW59_GKPa3ivLTAYgpafiY5HKPrCH')
resend.api_key = RESEND_API_KEY
SENDER_EMAIL = "onboarding@resend.dev"
SUPPORT_EMAIL = "support@larshield.com"
LOGO_URL = "https://i.ibb.co/3sXZbYm/larshieldlogowhite.png" # Temporary placeholder for LarShield logo
DASHBOARD_URL = "https://wss.larshield.com/dashboard" # Update with actual frontend URL
# Base path for templates depending on where the script runs from
TEMPLATES_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'templates', 'emails')
def render_template(template_name, context):
"""Reads the HTML file and replaces {{ keys }} with context values."""
filepath = os.path.join(TEMPLATES_DIR, template_name)
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# Inject standard variables
context["{{ year }}"] = str(datetime.now().year)
context["{{ logo_url }}"] = LOGO_URL
context["{{ support_email }}"] = SUPPORT_EMAIL
for key, value in context.items():
content = content.replace(key, str(value))
return content
except Exception as e:
print(f"[EmailService] Failed to render template {template_name}: {e}")
return ""
def _send_email_async(to_email, subject, html_content):
"""Sends the email in a background thread to avoid blocking the main request."""
def send():
import psycopg2
import uuid
db_url = os.environ.get('DATABASE_URL')
log_id = str(uuid.uuid4())
status = 'sent'
error_msg = None
try:
# FORCE ALL EMAILS TO THE TESTER EMAIL FOR RESEND FREE TIER LIMITATIONS
actual_to_email = "dhruvpatel14016@gmail.com"
r = resend.Emails.send({
"from": SENDER_EMAIL,
"to": actual_to_email,
"subject": subject,
"html": html_content
})
print(f"[EmailService] Email sent to {actual_to_email}. ID: {r['id']}")
except Exception as e:
status = 'failed'
error_msg = str(e)
print(f"[EmailService] Failed to send email to {to_email}: {e}")
finally:
if db_url:
try:
conn = psycopg2.connect(db_url)
cur = conn.cursor()
cur.execute(
"INSERT INTO email_logs (id, recipient, subject, status, error_message, sent_at) VALUES (%s, %s, %s, %s, %s, %s)",
(log_id, to_email, subject, status, error_msg, datetime.utcnow())
)
conn.commit()
cur.close()
conn.close()
except Exception as db_err:
print(f"[EmailService] Failed to log email to database: {db_err}")
thread = threading.Thread(target=send)
thread.start()
def send_welcome_email(user_email, user_name):
context = {
"{{ user_name }}": user_name,
"{{ dashboard_link }}": DASHBOARD_URL
}
html = render_template('welcome.html', context)
if html:
_send_email_async(user_email, "Welcome to LarShield!", html)
def send_scan_started(user_email, user_name, target_url, scan_type, estimated_time="~15 minutes"):
context = {
"{{ user_name }}": user_name,
"{{ target_url }}": target_url,
"{{ scan_type }}": scan_type,
"{{ estimated_time }}": estimated_time,
"{{ dashboard_link }}": DASHBOARD_URL
}
html = render_template('scan_started.html', context)
if html:
_send_email_async(user_email, "Scan Initiated Successfully", html)
def send_scan_completed(user_email, user_name, target_url, duration, vulns_count, report_link, crit="0", high="0", med="0", low="0"):
context = {
"{{ user_name }}": user_name,
"{{ target_url }}": target_url,
"{{ duration }}": duration,
"{{ vulns_count }}": vulns_count,
"{{ report_link }}": report_link,
"{{ crit_count }}": crit,
"{{ high_count }}": high,
"{{ med_count }}": med,
"{{ low_count }}": low
}
html = render_template('scan_completed.html', context)
if html:
_send_email_async(user_email, "Scan Completed Successfully", html)
def send_critical_alert(user_email, user_name, target_url, duration, vulns_count, report_link, crit="0", high="0", med="0", low="0"):
context = {
"{{ user_name }}": user_name,
"{{ target_url }}": target_url,
"{{ duration }}": duration,
"{{ vulns_count }}": vulns_count,
"{{ report_link }}": report_link,
"{{ crit_count }}": crit,
"{{ high_count }}": high,
"{{ med_count }}": med,
"{{ low_count }}": low
}
html = render_template('critical_alert.html', context)
if html:
_send_email_async(user_email, "🚨 URGENT: Critical Vulnerabilities Detected", html)
def send_scan_failed(user_email, user_name, target_url, scan_type, error_message):
context = {
"{{ user_name }}": user_name,
"{{ target_url }}": target_url,
"{{ scan_type }}": scan_type,
"{{ error_message }}": error_message,
"{{ dashboard_link }}": DASHBOARD_URL
}
html = render_template('scan_failed.html', context)
if html:
_send_email_async(user_email, "Scan Failed Alert", html)
def send_password_reset(user_email, user_name, reset_token):
reset_link = f"{DASHBOARD_URL}/reset-password?token={reset_token}"
context = {
"{{ user_name }}": user_name,
"{{ reset_link }}": reset_link
}
html = render_template('password_reset.html', context)
if html:
_send_email_async(user_email, "Password Reset Request", html)