import json
import base64
import os
import re
import sqlite3
from datetime import datetime, timedelta
from email.message import EmailMessage
from google.oauth2.credentials import Credentials
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
import random
import string
from dotenv import load_dotenv
load_dotenv(dotenv_path=os.path.join(os.environ.get('WORKSPACE_ROOT', '.'), 'backend/.env'))
# ==========================================
# APP CREDENTIALS (From your server.ts)
# ==========================================
CLIENT_ID = os.getenv('GOOGLE_CLIENT_ID')
CLIENT_SECRET = os.getenv('GOOGLE_CLIENT_SECRET')
def send_email_from_database(db_row_data, database_file='database.json', existing_unique_id=None):
"""
Constructs and sends an email using credentials dynamically loaded
from database.json, then saves the record to a follow-ups database.
"""
try:
# 1. Load User Credentials from database.json
if not os.path.exists(database_file):
print(f"Error: Could not find {database_file}")
return
with open(database_file, 'r') as f:
user_db_data = json.load(f)
access_token = user_db_data.get('access_token')
refresh_token = user_db_data.get('refresh_token')
sender_email = user_db_data.get('email')
# 2. Parse the target Email JSON from the database row
body_json_str = db_row_data.get('body_json', '{}')
data = json.loads(body_json_str)
# Extract necessary nested data
body_data = data.get('body', {})
generated_content = body_data.get('generated_content', '')
# Support both 'outreach_data' (new) and 'excel_data' (old)
outreach_data = body_data.get('outreach_data', body_data.get('excel_data', {}))
# Prioritize the flat database column (sanitized by UI) over the JSON blob
db_email = db_row_data.get('company_email')
recipient_email = db_email if db_email and db_email != 'not updated' else outreach_data.get('company_email')
if not recipient_email or not isinstance(recipient_email, str):
print(f"❌ Error: Invalid recipient email type: {type(recipient_email)} content: {recipient_email}")
return None
# Robust cleaning: remove anything that isn't a valid email character
recipient_email = "".join(c for c in recipient_email if c.isprintable()).strip().strip(',')
if '@' not in recipient_email:
print(f"❌ Error: Malformed email address: '{recipient_email}'")
return None
company_name = outreach_data.get('company_name', db_row_data.get('company_name', 'Unknown Company'))
# 3. Extract the Subject and HTML Body
subject = body_data.get('subject', db_row_data.get('generated_subject', "Partnership Inquiry"))
html_body = generated_content
# If the generated content has a Subject: header, parse it
match = re.match(r"(?i)Subject:\s*(.*?)(?:
|\n)+(.*)", generated_content, re.DOTALL)
if match:
subject = match.group(1).strip()
html_body = match.group(2).strip()
# Final sanitization of headers to prevent "Invalid Header" errors
subject = subject.replace('\n', ' ').replace('\r', ' ').strip()
recipient_email = recipient_email.strip()
# 4. Authenticate
creds = Credentials(
token=access_token,
refresh_token=refresh_token,
token_uri="https://oauth2.googleapis.com/token",
client_id=CLIENT_ID, # <-- Added
client_secret=CLIENT_SECRET, # <-- Added
scopes=["https://www.googleapis.com/auth/gmail.send"]
)
# Force a token refresh if it has expired
if creds and creds.expired and creds.refresh_token:
print("Access token expired. Refreshing token automatically...")
creds.refresh(Request())
# Optional: You could write the newly refreshed access_token back to your database.json here
# so the next run is faster, but it's not strictly necessary since the library handles it in memory!
# 5. Construct the Email Message
message = EmailMessage()
message["To"] = recipient_email
message["From"] = sender_email.strip() if sender_email else ""
message["Subject"] = subject
# --- Robust HTML Formatting ---
if '
' not in html_body and '
text
html_body = re.sub(r"\*\*(.*?)\*\*", r"\1", html_body)
# Handle Markdown-style bullet points - text -> • text
lines = html_body.split('\n')
for i, line in enumerate(lines):
s_line = line.strip()
if s_line.startswith('- '):
lines[i] = '• ' + s_line[2:]
html_body = '\n'.join(lines)
# Split by double newline for paragraphs
paragraphs = [p.strip() for p in html_body.split('\n\n') if p.strip()]
if len(paragraphs) > 1:
html_body = "".join("
" + p.replace('\n', '
') + "