Untitled

 avatar
unknown
plain_text
a month ago
10 kB
2
Indexable
import pandas as pd
import smtplib
import tkinter as tk
import os
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from docx import Document
from tkinter import filedialog
from tkinter import messagebox
from tkinter import ttk
from dotenv import load_dotenv

# Function to read text from a Word document and convert custom HTML-like tags to real HTML tags
def extract_text_from_word(docx_file_path):
    doc = Document(docx_file_path)
    extracted_text = ""

    for para in doc.paragraphs:
        para_text = para.text
        extracted_text += para_text + "\n"

    return extracted_text

# Function to convert a DataFrame to styled HTML
def dataframe_to_styled_html(df, merge_first_row=False):
    table_style = (
        "border-collapse: collapse; width: 65%; font-family: Arial, sans-serif; "
        "font-size: 14px; text-align: center;"
    )
    header_style = (
        "background-color: #6A0DAD; color: white; padding: 10px; border: 1px solid black;"
    )
    cell_style = "padding: 10px; border: 1px solid black;"
    row_alt_style = "background-color: #f2f2f2;"

    html_table = f'<table style="{table_style}">'

    # Merge first row if requested
    if merge_first_row:
        html_table += f'<tr><td colspan="{len(df.columns)}" style="{header_style}">{df.columns[0]}</td></tr>'
    else:
        # Add table headers
        html_table += "<tr>"
        for col in df.columns:
            html_table += f'<th style="{header_style}">{col}</th>'
        html_table += "</tr>"

    # Add table rows
    for i, row in df.iterrows():
        row_style = row_alt_style if i % 2 == 1 else ""
        html_table += f'<tr style="{row_style}">'
        for cell in row:
            if pd.isna(cell):
                cell_content = ""
            else:
                if isinstance(cell, float):
                    cell_content = f"{cell:.2%}" if 0 <= cell <= 1 else cell
                else:
                    cell_content = cell
            html_table += f'<td style="{cell_style}">{cell_content}</td>'
        html_table += "</tr>"

    html_table += "</table>"
    return html_table

# Function to send bulk emails with text and tables
def send_bulk_emails_with_text_and_tables(
    sender_email,
    sender_password,
    smtp_server,
    smtp_port,
    email_list_file,
    table1_file,
    table2_file,
    text_file,
    log_text_widget,
    log_file
):
    log_serial_number = 1
    
    with open(log_file, 'a') as log_file_obj:

        # Read the email list from an Excel file
        email_data = pd.read_excel(email_list_file)
        if "Email" not in email_data.columns or "Salutations" not in email_data.columns or "CC" not in email_data.columns:
            log_text_widget.insert(tk.END, "The email list file must contain columns: 'Email', 'Salutations', and 'CC'.\n")
            return

        email_details = email_data[["Email", "Salutations", "CC"]]

        if text_file.endswith(".docx"):
            email_text = extract_text_from_word(text_file)
        else:
            log_text_widget.insert(tk.END, "Unsupported file format. Use a .docx file for the text.\n")
            return

        table1_df = pd.read_excel(table1_file)
        table2_df = pd.read_excel(table2_file)

        table1_html = dataframe_to_styled_html(table1_df)
        table2_html = dataframe_to_styled_html(table2_df, merge_first_row=True)

        if "{{ TABLE_1 }}" in email_text:
            email_text = email_text.replace("{{ TABLE_1 }}", table1_html)
        else:
            log_text_widget.insert(tk.END, "Placeholder {{ TABLE_1 }} not found in the text.\n")

        if "{{ TABLE_2 }}" in email_text:
            email_text = email_text.replace("{{ TABLE_2 }}", table2_html)
        else:
            log_text_widget.insert(tk.END, "Placeholder {{ TABLE_2 }} not found in the text.\n")

        email_body_html = f"""
        <html>
            <body>
                {email_text}
            </body>
        </html>
        """

        try:
            with smtplib.SMTP(smtp_server, smtp_port) as server:
                server.starttls()
                server.login(sender_email, sender_password)

                for _, row in email_details.iterrows():
                    try:
                        recipients = row["Email"].split(",")
                        salutation = row["Salutations"]
                        cc_list = row["CC"].split(",") if pd.notna(row["CC"]) else []

                        personalized_text = email_body_html.replace("{{ Salutations }}", salutation)

                        msg = MIMEMultipart()
                        msg["From"] = sender_email
                        msg["To"] = ", ".join(recipients)
                        msg["Cc"] = ", ".join(cc_list)
                        msg["Subject"] = "Your Wealth Management Summary"

                        msg.attach(MIMEText(personalized_text, "html"))

                        all_recipients = recipients + cc_list
                        server.sendmail(sender_email, all_recipients, msg.as_string())

                        log_text_widget.insert(tk.END, f"{log_serial_number}. Email sent successfully to {', '.join(recipients)}, CC: {', '.join(cc_list)}\n")
                        log_text_widget.yview(tk.END)
                        log_file_obj.write(f"{log_serial_number}. Email sent successfully to {', '.join(recipients)}, CC: {', '.join(cc_list)}\n")

                    except Exception as e:
                        log_text_widget.insert(tk.END, f"{log_serial_number}. Failed to send email to {', '.join(recipients)}: {e}\n")
                        log_text_widget.yview(tk.END)
                        log_file_obj.write(f"{log_serial_number}. Failed to send email to {', '.join(recipients)}: {e}\n")

                    log_serial_number += 1

        except Exception as e:
            log_text_widget.insert(tk.END, f"Failed to connect to the SMTP server: {e}\n")
            log_text_widget.yview(tk.END)
            log_file_obj.write(f"Failed to connect to the SMTP server: {e}\n")

# Remaining code (UI setup) remains the same.


# Function to browse file
def browse_file(entry):
    # Open file dialog to select a file and set the path to the entry
    file_path = filedialog.askopenfilename(title="Select a file", filetypes=[("Excel files", "*.xlsx"), ("Text files", "*.txt"), ("PDF files", "*.pdf"), ("Word files", "*.docx")])
    if file_path:
        entry.delete(0, tk.END)  # Clear existing content
        entry.insert(0, file_path)  # Insert selected file path


# Function to handle the send email button click
def send_email_ui():
    sender_email = sender_email_entry.get()
    sender_password = sender_password_entry.get()
    email_list_file = email_list_entry.get()
    table1_file = table1_entry.get()
    table2_file = table2_entry.get()
    text_file = text_file_entry.get()
    smtp_server = "smtp.gmail.com"
    smtp_port = 587
    log_file = "email_log.txt"  # Log file path

    if not all([sender_email, sender_password, email_list_file, table1_file, table2_file, text_file]):
        messagebox.showerror("Missing Information", "Please fill in all fields before sending.")
    else:
        # Call the send_bulk_emails_with_text_and_tables function with the inputs
        send_bulk_emails_with_text_and_tables(
            sender_email,
            sender_password,
            smtp_server,
            smtp_port,
            email_list_file,
            table1_file,
            table2_file,
            text_file,
            log_text_widget,
            log_file
        )
        messagebox.showinfo("Task Complete", "All emails have been sent successfully!")


#env
load_dotenv()
sender_password = os.getenv("SENDER_PASSWORD", "")
sender_email = os.getenv("SENDER_EMAIL", "")
#print(os.getenv("SENDER_PASSWORD",""))


# Create the main window
root = tk.Tk()
root.title("Pygmalion Wealth")  # Set the window title

# Sender Email
tk.Label(root, text="Sender Email:").grid(row=0, column=0, padx=10, pady=5)
sender_email_entry = tk.Entry(root, width=40)
sender_email_entry.insert(0, sender_email)
sender_email_entry.grid(row=0, column=1, padx=10, pady=5)

# Sender Password
tk.Label(root, text="Sender Password:").grid(row=1, column=0, padx=10, pady=5)
sender_password_entry = tk.Entry(root, width=40, show="*")
sender_password_entry.insert(0,sender_password)
sender_password_entry.grid(row=1, column=1, padx=10, pady=5)

# Email List File
tk.Label(root, text="Email List File:").grid(row=2, column=0, padx=10, pady=5)
email_list_entry = tk.Entry(root, width=40)
email_list_entry.grid(row=2, column=1, padx=10, pady=5)
tk.Button(root, text="Browse", command=lambda: browse_file(email_list_entry)).grid(row=2, column=2, padx=10, pady=5)

# Table 1 File
tk.Label(root, text="Table 1 File:").grid(row=3, column=0, padx=10, pady=5)
table1_entry = tk.Entry(root, width=40)
table1_entry.grid(row=3, column=1, padx=10, pady=5)
tk.Button(root, text="Browse", command=lambda: browse_file(table1_entry)).grid(row=3, column=2, padx=10, pady=5)

# Table 2 File
tk.Label(root, text="Table 2 File:").grid(row=4, column=0, padx=10, pady=5)
table2_entry = tk.Entry(root, width=40)
table2_entry.grid(row=4, column=1, padx=10, pady=5)
tk.Button(root, text="Browse", command=lambda: browse_file(table2_entry)).grid(row=4, column=2, padx=10, pady=5)

# Text File
tk.Label(root, text="Text File:").grid(row=5, column=0, padx=10, pady=5)
text_file_entry = tk.Entry(root, width=40)
text_file_entry.grid(row=5, column=1, padx=10, pady=5)
tk.Button(root, text="Browse", command=lambda: browse_file(text_file_entry)).grid(row=5, column=2, padx=10, pady=5)

# Log Text Widget (for display)
log_text_widget = tk.Text(root, height=10, width=80, wrap=tk.WORD, font=("Arial", 10))
log_text_widget.grid(row=6, column=0, columnspan=3, padx=10, pady=5)

# Send Email Button
send_button = tk.Button(root, text="Send Emails", command=send_email_ui)
send_button.grid(row=7, column=0, padx=10, pady=10)

#exit program button
exit_button = tk.Button(root, text="Exit", command=root.quit)
exit_button.grid(row=7, column=3, padx=10, pady=10)

# Start the Tkinter event loop
root.mainloop()
Leave a Comment