├── .env.sample ├── requirements.txt ├── .gitignore ├── texts.py ├── README.md ├── main.py └── emailer.py /.env.sample: -------------------------------------------------------------------------------- 1 | SENDER_EMAIL= 2 | SENDER_PASSWORD= -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | openpyxl 2 | python-decouple -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .env 3 | *.xlsx 4 | *.html -------------------------------------------------------------------------------- /texts.py: -------------------------------------------------------------------------------- 1 | class texts: 2 | SUBJECT = """ 3 | This is a subject. 4 | """ 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EmailFromCSV 2 | - `SENDER_EMAIL` - email 3 | - `SENDER_PASSWORD` - app password from https://myaccount.google.com/u/3/apppasswords -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import openpyxl 2 | import tabulate 3 | from emailer import send_email 4 | 5 | path = "./data.xlsx" 6 | 7 | 8 | def main(): 9 | workbook = openpyxl.load_workbook(path) 10 | sheet = workbook.active 11 | name_email_list = [] 12 | for row in sheet.iter_rows(values_only=True): 13 | if row[0] == "Name" or row[1] == "Email": # skip header row 14 | continue 15 | name_email_list.append((row[0], row[1])) 16 | done, failed = send_email(name_email_list) 17 | if done: 18 | tabulated_done = tabulate.tabulate( 19 | [[mail] for mail in done], 20 | headers=[f"Emails: Success {len(done)}"], 21 | tablefmt="grid", 22 | ) 23 | print(tabulated_done) 24 | if failed: 25 | tabulated_failed = tabulate.tabulate( 26 | [[mail] for mail in failed], headers=[f"Emails: Failed - {len(failed)}"] 27 | ) 28 | print(tabulated_failed) 29 | workbook.close() 30 | 31 | 32 | main() 33 | -------------------------------------------------------------------------------- /emailer.py: -------------------------------------------------------------------------------- 1 | from decouple import config 2 | import smtplib 3 | from email.mime.text import MIMEText 4 | from email.mime.multipart import MIMEMultipart 5 | 6 | from texts import texts 7 | 8 | sender_email = config("SENDER_EMAIL", default=None) 9 | sender_password = config("SENDER_PASSWORD", default=None) 10 | 11 | if not sender_email or not sender_password: 12 | raise Exception("Please provide sender email and password") 13 | 14 | # with open("content.html") as f: 15 | # data = f.read() 16 | 17 | data = "hello there <#name>" 18 | 19 | 20 | def send_email(email_name_list): 21 | done = [] 22 | failed = [] 23 | with smtplib.SMTP("smtp.gmail.com", 587) as server: 24 | server.starttls() 25 | server.login(sender_email, sender_password) 26 | 27 | for name, email in email_name_list: 28 | message = MIMEMultipart() 29 | message["From"] = sender_email 30 | message["To"] = email 31 | message["Subject"] = texts.SUBJECT 32 | data = data.replace("<#name>", name) 33 | 34 | message.attach(MIMEText(data, "plain")) 35 | # message.attach(MIMEText(data, "html")) 36 | 37 | try: 38 | server.sendmail(sender_email, email, message.as_string()) 39 | done.append(email) 40 | except Exception as e: 41 | failed.append(email) 42 | print(f"Error sending to {email}: {e}") 43 | return done, failed 44 | --------------------------------------------------------------------------------