Skip to content

Commit e0e2818

Browse files
Create bulk_email.py
The Bulk Email Sender — Pro+ Edition is a modern, Python-based web application built with Streamlit that allows individuals and businesses to send personalized bulk emails quickly, securely, and efficiently. The application is designed for users who need to manage email campaigns, notifications, or bulk communication without using expensive third-party services. Unlike generic mass-mailing tools, this application supports personalization, attachments, manual email entries, and live progress monitoring, making it ideal for small businesses, freelancers, or teams who want a simple yet professional emailing solution.
1 parent d7e7324 commit e0e2818

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import smtplib
2+
from email.mime.text import MIMEText
3+
from email.mime.multipart import MIMEMultipart
4+
from email.mime.base import MIMEBase
5+
from email import encoders
6+
import pandas as pd
7+
import streamlit as st
8+
import time
9+
import os
10+
11+
# ---------------- Streamlit Page Config ----------------
12+
st.set_page_config(page_title="📧 Bulk Email Pro+ Dashboard", page_icon="📨", layout="centered")
13+
st.title("📨 Bulk Email Sender — Pro+ Edition")
14+
st.caption("Send personalized bulk emails with live logs, attachments, and custom names")
15+
16+
st.markdown("---")
17+
18+
# ---------------- Email Login Section ----------------
19+
with st.expander("🔑 Gmail Login Details"):
20+
sender_name = st.text_input("Sender Name (appears in inbox)", placeholder="Your Name")
21+
sender_email = st.text_input("Your Gmail Address", placeholder="youremail@gmail.com")
22+
sender_password = st.text_input("App Password", type="password", placeholder="16-character Gmail App Password")
23+
24+
# ---------------- CSV Upload ----------------
25+
uploaded_file = st.file_uploader("📂 Upload CSV (columns: Name, Email)", type=["csv"])
26+
27+
st.markdown("""
28+
**Example CSV format:**
29+
| Name | Email |
30+
|------|--------------------|
31+
| Rahul Pandey | rahul@example.com |
32+
| Riya Sharma | riya@example.com |
33+
""")
34+
35+
# ---------------- Manual Email Entry ----------------
36+
with st.expander("✏️ Add Optional Emails Manually"):
37+
manual_emails = st.text_area(
38+
"Enter additional emails manually (format: Name:Email, separated by commas)",
39+
placeholder="Rahul Pandey:rahul@gmail.com, Riya Sharma:riya@gmail.com"
40+
)
41+
42+
# ---------------- Email Content ----------------
43+
subject = st.text_input("✉️ Email Subject", placeholder="Hello {Name}, here’s your update!")
44+
message_template = st.text_area(
45+
"📝 Email Body (you can use placeholders like {Name})",
46+
height=150,
47+
placeholder="Dear {Name},\n\nHope you're doing well!\n\nBest regards,\nYour Name"
48+
)
49+
50+
# ---------------- File Attachment ----------------
51+
attachment = st.file_uploader("📎 Optional: Attach a file (PDF, Image, or DOCX)", type=["pdf", "jpg", "jpeg", "png", "docx"])
52+
53+
# ---------------- Email Preview ----------------
54+
if st.button("👁️ Preview Email"):
55+
if uploaded_file:
56+
df_preview = pd.read_csv(uploaded_file)
57+
if "Name" in df_preview.columns and len(df_preview) > 0:
58+
name_sample = df_preview["Name"][0]
59+
st.markdown("### 🧾 Preview for first recipient:")
60+
st.info(f"**Subject:** {subject.format(Name=name_sample)}\n\n{message_template.format(Name=name_sample)}")
61+
else:
62+
st.warning("CSV must have a 'Name' column with at least one entry.")
63+
else:
64+
st.warning("Please upload a CSV first.")
65+
66+
# ---------------- Send Button ----------------
67+
if st.button("🚀 Send Emails"):
68+
if not sender_email or not sender_password:
69+
st.error("Please enter your Gmail and App Password.")
70+
elif uploaded_file is None and not manual_emails:
71+
st.error("Please upload a CSV file or enter emails manually.")
72+
else:
73+
try:
74+
recipients = []
75+
76+
# Load from CSV if available
77+
if uploaded_file is not None:
78+
df = pd.read_csv(uploaded_file)
79+
if "Email" not in df.columns or "Name" not in df.columns:
80+
st.error("CSV must contain columns 'Name' and 'Email'.")
81+
st.stop()
82+
for _, row in df.iterrows():
83+
recipients.append({"Name": row["Name"], "Email": row["Email"]})
84+
85+
# Add manual emails (support Name:Email or just Email)
86+
if manual_emails:
87+
for entry in [e.strip() for e in manual_emails.split(",") if e.strip()]:
88+
if ":" in entry:
89+
name, email = entry.split(":", 1)
90+
recipients.append({"Name": name.strip(), "Email": email.strip()})
91+
else:
92+
recipients.append({"Name": "Friend", "Email": entry.strip()})
93+
94+
# Connect to Gmail
95+
server = smtplib.SMTP("smtp.gmail.com", 587)
96+
server.starttls()
97+
server.login(sender_email, sender_password)
98+
st.success("✅ Logged in successfully!")
99+
100+
# UI Setup: progress bar + live logs
101+
progress = st.progress(0)
102+
status = st.empty()
103+
log_box = st.container()
104+
total = len(recipients)
105+
success_count = 0
106+
107+
# ---------------- Sending Loop ----------------
108+
for i, recipient in enumerate(recipients):
109+
recipient_email = recipient["Email"]
110+
recipient_name = recipient["Name"]
111+
112+
msg = MIMEMultipart()
113+
msg["From"] = f"{sender_name} <{sender_email}>"
114+
msg["To"] = recipient_email
115+
msg["Subject"] = subject.format(Name=recipient_name)
116+
117+
# Message body
118+
body = message_template.format(Name=recipient_name)
119+
msg.attach(MIMEText(body, "plain"))
120+
121+
# Add attachment if uploaded
122+
if attachment is not None:
123+
part = MIMEBase("application", "octet-stream")
124+
part.set_payload(attachment.getvalue())
125+
encoders.encode_base64(part)
126+
part.add_header(
127+
"Content-Disposition",
128+
f"attachment; filename={attachment.name}"
129+
)
130+
msg.attach(part)
131+
132+
# Send email and log live
133+
try:
134+
server.send_message(msg)
135+
success_count += 1
136+
with log_box:
137+
st.markdown(f"✅ **Sent to {recipient_name}** ({recipient_email})")
138+
except Exception as e:
139+
with log_box:
140+
st.markdown(f"⚠️ **Failed to send to {recipient_email}:** {e}")
141+
142+
# Update progress bar
143+
progress.progress((i + 1) / total)
144+
status.text(f"📨 Sending email {i+1}/{total}...")
145+
146+
time.sleep(0.5)
147+
148+
server.quit()
149+
st.success(f"✅ Successfully sent {success_count}/{total} emails!")
150+
st.balloons()
151+
152+
except Exception as e:
153+
st.error(f"❌ Error: {e}")

0 commit comments

Comments
 (0)