Spaces:
Sleeping
Sleeping
Update modules/email_handler.py
Browse files- modules/email_handler.py +54 -32
modules/email_handler.py
CHANGED
|
@@ -1,65 +1,87 @@
|
|
| 1 |
-
# email_handler.py
|
| 2 |
-
|
| 3 |
import smtplib
|
| 4 |
from email.mime.multipart import MIMEMultipart
|
| 5 |
from email.mime.text import MIMEText
|
| 6 |
from email.mime.application import MIMEApplication
|
| 7 |
import os
|
| 8 |
import ssl
|
|
|
|
| 9 |
|
| 10 |
class EmailHandler:
|
| 11 |
def __init__(self):
|
| 12 |
self.smtp_server = "smtp.gmail.com"
|
| 13 |
-
|
| 14 |
-
self.smtp_port = 465 # Changed to SSL port
|
| 15 |
self.sender_email = os.getenv('GMAIL_USER')
|
| 16 |
self.sender_password = os.getenv('GMAIL_APP_PASSWORD')
|
| 17 |
|
| 18 |
# Verify credentials
|
| 19 |
if not self.sender_email or not self.sender_password:
|
| 20 |
-
raise ValueError("Email credentials not properly configured")
|
| 21 |
|
| 22 |
-
|
| 23 |
def send_invoice(self, recipient_email, workflow_state_dict, invoice_path):
|
| 24 |
"""Send invoice email with retry mechanism"""
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
|
|
|
|
|
|
| 32 |
|
|
|
|
| 33 |
Your payment of {workflow_state_dict['invoice']['currency']} {workflow_state_dict['invoice']['billed_amount']} is due by {workflow_state_dict['invoice']['payment_due_date']}.
|
| 34 |
Please do the payment at the earliest.
|
| 35 |
-
|
| 36 |
Best regards,
|
| 37 |
Your Company Name"""
|
| 38 |
|
| 39 |
-
|
| 40 |
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
filename=os.path.basename(invoice_path))
|
| 46 |
-
|
| 47 |
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
self.smtp_port,
|
| 53 |
-
context=context,
|
| 54 |
-
) as server:
|
| 55 |
print("Connected to SMTP server")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
server.login(self.sender_email, self.sender_password)
|
| 57 |
print("Login successful")
|
|
|
|
|
|
|
| 58 |
server.send_message(msg)
|
| 59 |
print("Email sent successfully")
|
| 60 |
return True
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import smtplib
|
| 2 |
from email.mime.multipart import MIMEMultipart
|
| 3 |
from email.mime.text import MIMEText
|
| 4 |
from email.mime.application import MIMEApplication
|
| 5 |
import os
|
| 6 |
import ssl
|
| 7 |
+
import time
|
| 8 |
|
| 9 |
class EmailHandler:
|
| 10 |
def __init__(self):
|
| 11 |
self.smtp_server = "smtp.gmail.com"
|
| 12 |
+
self.smtp_port = 587 # Using TLS port instead of SSL
|
|
|
|
| 13 |
self.sender_email = os.getenv('GMAIL_USER')
|
| 14 |
self.sender_password = os.getenv('GMAIL_APP_PASSWORD')
|
| 15 |
|
| 16 |
# Verify credentials
|
| 17 |
if not self.sender_email or not self.sender_password:
|
| 18 |
+
raise ValueError("Email credentials not properly configured. Please check GMAIL_USER and GMAIL_APP_PASSWORD environment variables.")
|
| 19 |
|
|
|
|
| 20 |
def send_invoice(self, recipient_email, workflow_state_dict, invoice_path):
|
| 21 |
"""Send invoice email with retry mechanism"""
|
| 22 |
+
max_retries = 3
|
| 23 |
+
retry_delay = 2
|
| 24 |
+
|
| 25 |
+
for attempt in range(max_retries):
|
| 26 |
+
try:
|
| 27 |
+
msg = MIMEMultipart()
|
| 28 |
+
msg['From'] = self.sender_email
|
| 29 |
+
msg['To'] = recipient_email
|
| 30 |
+
msg['Subject'] = f"Invoice #{workflow_state_dict['invoice']['transaction_id']} - Payment Due"
|
| 31 |
|
| 32 |
+
body = f"""Dear {workflow_state_dict['customer']['cust_fname']},
|
| 33 |
Your payment of {workflow_state_dict['invoice']['currency']} {workflow_state_dict['invoice']['billed_amount']} is due by {workflow_state_dict['invoice']['payment_due_date']}.
|
| 34 |
Please do the payment at the earliest.
|
|
|
|
| 35 |
Best regards,
|
| 36 |
Your Company Name"""
|
| 37 |
|
| 38 |
+
msg.attach(MIMEText(body, 'plain'))
|
| 39 |
|
| 40 |
+
# Attach PDF
|
| 41 |
+
with open(invoice_path, "rb") as f:
|
| 42 |
+
pdf = MIMEApplication(f.read(), _subtype="pdf")
|
| 43 |
+
pdf.add_header('Content-Disposition', 'attachment',
|
| 44 |
filename=os.path.basename(invoice_path))
|
| 45 |
+
msg.attach(pdf)
|
| 46 |
|
| 47 |
+
print(f"Attempt {attempt + 1}: Connecting to Gmail SMTP server...")
|
| 48 |
+
|
| 49 |
+
# Using SMTP with TLS
|
| 50 |
+
with smtplib.SMTP(self.smtp_server, self.smtp_port, timeout=30) as server:
|
|
|
|
|
|
|
|
|
|
| 51 |
print("Connected to SMTP server")
|
| 52 |
+
server.ehlo() # Identify ourselves to the server
|
| 53 |
+
print("Starting TLS encryption...")
|
| 54 |
+
server.starttls(context=ssl.create_default_context())
|
| 55 |
+
server.ehlo() # Re-identify ourselves over TLS connection
|
| 56 |
+
print("TLS encryption established")
|
| 57 |
+
|
| 58 |
+
print("Attempting login...")
|
| 59 |
server.login(self.sender_email, self.sender_password)
|
| 60 |
print("Login successful")
|
| 61 |
+
|
| 62 |
+
print("Sending email...")
|
| 63 |
server.send_message(msg)
|
| 64 |
print("Email sent successfully")
|
| 65 |
return True
|
| 66 |
+
|
| 67 |
+
except smtplib.SMTPAuthenticationError as e:
|
| 68 |
+
print(f"Authentication failed. Please check your Gmail credentials and ensure you're using an App Password.")
|
| 69 |
+
print(f"Error details: {str(e)}")
|
| 70 |
+
return False
|
| 71 |
+
|
| 72 |
+
except smtplib.SMTPException as e:
|
| 73 |
+
print(f"SMTP error on attempt {attempt + 1}: {str(e)}")
|
| 74 |
+
if attempt < max_retries - 1:
|
| 75 |
+
print(f"Retrying in {retry_delay} seconds...")
|
| 76 |
+
time.sleep(retry_delay)
|
| 77 |
+
continue
|
| 78 |
+
|
| 79 |
+
except Exception as e:
|
| 80 |
+
print(f"Unexpected error on attempt {attempt + 1}: {str(e)}")
|
| 81 |
+
print(f"Error type: {type(e)}")
|
| 82 |
+
if attempt < max_retries - 1:
|
| 83 |
+
print(f"Retrying in {retry_delay} seconds...")
|
| 84 |
+
time.sleep(retry_delay)
|
| 85 |
+
continue
|
| 86 |
+
|
| 87 |
+
return False
|