<reponame>kyang6/Auto-Emailer
import time
import random
import json
import sys
import csv
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from random import randint


# Make sure requirements are installed using: pip install -r requirements.txt

# JSON contacts file should look like this: [{"emails":["<EMAIL>"],"name":"James"},\
#   {"emails":["<EMAIL>"],"name":"Kevin"},{"emails":["<EMAIL>"],"name":"Will"}] 

class Emailer:
    """ This class leverages gmail to send emails to many contacts at once
    
    How to Use

        from emailer import Emailer  

        msg = [
        'Hey __receiver__,',
        'I\'m __sender_name__, a fellow Stanford student studying computer science. I\'m working on an intense class project where we interview professionals to find needs and problems in industries, and later build software solutions for free.',
        'We\'re trying our best to learn more about different industries out there.',
        'It\'d be great to hear about advice, your biggest pain points, and what\'s generally on your mind in regards to your industy. Maybe we can build something together!\n\nWould you have any time to chat on phone? Email is also great too!',
        'Thanks so much,',
        '__sender_name__'
        ]

        subject = "Test Subject Line"

        emailer = Emailer(email_body=msg, subject_line=subject, sender_name="Kevin", contacts_file = "test.txt", \
            path_to_driver="/Users/KevinYang/Documents/chromedriver")

        emailer.custom_login()
        emailer.send_emails()
    """
    def __init__(self, contacts_file, cc=[], file_type='JSON', username_email="__None__", password="__<PASSWORD>", \
        email_body="__Default_Email_Body__", subject_line="__Default_Subject_Line__", \
        sender_name = "__Default_Sender_Name__", path_to_driver = "No Path Specified"):
        """
            The parameters are as follows

            contacts_file - name of the json file. Example- chevron.txt
            file_type- the type of file that contacts_file is. Currently only JSON is supported
            username_email- gmail email used to auto login if so desired (Required for auto_login)
            password- gmail password used to auto login if so desired (Required for auto_login)
            email_body - an array of lines that will be joined with \n\n later. Example
                [
                'Hey __receiver__,',
                'I\'m __sender_name__, a fellow Stanford student studying computer science. I\'m working on an intense 
                class project where we interview professionals to find needs and problems in industries, and later 
                build software solutions for free.',
                '__misc__',
                'I would love to be able to talk to you!',
                'Thanks so much,',
                '__sender_name__'
                ]

            subject_line - subject line
            sender_name - The name of the person who is sending the email.
            path_to_driver - Path to chrome driver (Required to work)
        """
        self.file_name = contacts_file
        if(self.file_name.rsplit(".",1)[-1]=="csv"):
            file_type = 'CSV'

        self.contacts = []
        if file_type == 'JSON':
            self.file_type = 'JSON'
            try:
                print(contacts_file)
                with open(contacts_file) as json_data:
                    contacts = json.load(json_data)

                self.contacts = []
                for name in contacts: 
                    self.contacts.append({
                        'name': name,
                        'emails': [contacts[name]]
                    })

            except:
                print("Error reading in JSON file", sys.exc_info()[0])

        elif file_type == 'CSV':
            try:
                self.read_csv()
            except:
                print("Failed reading in CSV file", sys.exc_info()[0])

        self.username_email = username_email
        self.password = password

        self.driver = webdriver.Chrome(path_to_driver)

        self.subject_line = subject_line
        self.email_body = email_body
        self.sender_name = sender_name
        self.cc = cc

    # Reads in contacts from a CSV file. Look at the provided example for a sample.
    def read_csv(self):
        with open(self.file_name, 'r') as csvfile:
            reader = csv.DictReader(csvfile)
            for row in reader:
                self.contacts.append({"name":row['name'], "emails":row['emails'].split(",")})

    # Login to custom email. You need to type in your own information and login
    # You have timeout_time seconds to login before timeout
    def custom_login(self):
        self.driver.get("https://mail.google.com/?ui=html")
        timeout_time = 60
        print("You have {0} seconds to login".format(str(timeout_time)))
        try:
            element = WebDriverWait(self.driver, timeout_time).until(
                EC.title_contains("-")
            )
        finally: 
            print("Gmail loaded and ready")
            self.driver.get("https://mail.google.com/?ui=html")

    # Sends one email to email_address with subject and body and cc 
    def send_email(self, email_addresses, subject, body, cc):
        print("Sending emails to {} contacts.".format(len(self.contacts)))

        try:
            element = WebDriverWait(self.driver, 20).until(
                EC.title_contains("- Inbox")
            )
        finally: 
            print("Gmail loaded and ready")

        compose = self.driver.find_element_by_xpath("/html/body/table[2]/tbody/tr/td[1]/table[1]/tbody/tr[1]/td/b/a")
        compose.click()
        
        try:
            element = WebDriverWait(self.driver, 20).until(
                EC.visibility_of_element_located((By.ID, "to"))
            )
        finally: 
            print("Compose page loaded and ready")

        to_area = self.driver.find_element_by_id("to")

        for email in email_addresses:
            # workaround for formatting issue when downloading emails saved to airtable
            to_area.send_keys(email.replace("\'","").replace("[","").replace("]",""))
            to_area.send_keys(", ")

        cc_area = self.driver.find_element_by_id("cc")
        for email in cc:
            cc_area.send_keys(email)
            cc_area.send_keys(", ")

        subject_area = self.driver.find_element_by_xpath("/html/body/table[2]/tbody/tr/td[2]/table[1]/tbody/tr/td[2]/form/table[2]/tbody/tr[4]/td[2]/input")
        subject_area.send_keys(subject)

        # called 
        self.writeBodyText(self.email_body)

        send_button = self.driver.find_element_by_xpath("/html/body/table[2]/tbody/tr/td[2]/table[1]/tbody/tr/td[2]/form/table[1]/tbody/tr/td/input[1]")

        # Wait random number of milliseconds before sending
        time.sleep(random.uniform(0, 1))
        send_button.click()
    
    # Returns a template email. 
    def email_template(self, receiver="__None__", misc="__None__", clean_receiver=False):
        if clean_receiver:
            receiver = receiver.replace('Ms.', '').replace('Mr.', '').replace('Dr.', '').strip().split(' ')[0]
        
        msg = self.email_body

        msg = '\n\n'.join(msg)
        msg = msg.replace("__receiver__", receiver.split(" ")[0])
        msg = msg.replace("__sender_name__", self.sender_name)
        msg = msg.replace("__misc__", misc)

        return msg

    # Automatically logs in 
    def auto_login(self):
        if self.username_email == "__None__" or self.password == "__<PASSWORD>__":
            print("auto_login requires a username_email and a password." \
                " Make sure to provide both during instantiation.")
            exit()

        print("auto_login is not recommended. Be wary, as your password will be in plaintext")

        self.driver.get("https://mail.google.com/?ui=html")

        emailid=self.driver.find_element_by_id("identifierId")
        emailid.send_keys(self.username_email)

        next_button = self.driver.find_element_by_id('identifierNext')
        next_button.click()
        try:
            element = WebDriverWait(self.driver, 5).until(
                EC.visibility_of_element_located((By.ID, "password"))
            )
        finally: 
            print("Password page loaded")

        password = self.driver.find_element_by_id("password").find_element_by_tag_name("input")
        password.send_keys(<PASSWORD>)
        sign_in = self.driver.find_element_by_id("passwordNext")
        sign_in.click()

        try:
            element = WebDriverWait(self.driver, 2).until(
                EC.title_contains("Do you really want to use HTML Gmail?")
            )
        except:
            print("Simple HTML page not shown.")
        else:
            confirm_html = self.driver.find_element_by_css_selector("input[type='submit']")
            confirm_html.click()

        try:
            element = WebDriverWait(self.driver, 20).until(
                EC.title_contains("Gmail - Inbox")
            )
        finally: 
            print("Gmail loaded and ready")
            self.driver.get("https://mail.google.com/?ui=html")

    def send_emails(self):
        print("Sending emails...")
        for contact in self.contacts:
            time.sleep(randint(1,5)*0.6)
            if len(contact['emails'])==0: continue
            
            if 'misc' in contact:
                misc = contact['misc']
            else:
                misc = "__None__"
            if 'name' in contact:
                receiver = contact['name']
            else:
                receiver = "__None__"

            self.receiver = receiver
            self.misc = misc
            mail_temp = self.email_template(receiver=receiver,misc=misc)

            self.send_email(contact['emails'], self.subject_line, mail_temp, self.cc)
            print("Email sent to {0} at {1}".format(contact['name'],str(contact['emails'])))

    def writeBodyText(self, email_body):
        for line in email_body:
            line = line.replace("__receiver__", self.receiver.split(" ")[0])
            line = line.replace("__sender_name__", self.sender_name)
            line = line.replace("__misc__", self.misc)

            self.driver.execute_script('''
                document.evaluate(
                    '/html/body/table[2]/tbody/tr/td[2]/table[1]/tbody/tr/td[2]/form/table[2]/tbody/tr[8]/td[2]/textarea',  
                    document
                ).iterateNext().value += '{}';
            '''.format(line))
            
            body_area = self.driver.find_element_by_xpath("/html/body/table[2]/tbody/tr/td[2]/table[1]/tbody/tr/td[2]/form/table[2]/tbody/tr[8]/td[2]/textarea")
            body_area.send_keys('\n\n')



# ---------------------------------------------------------- #
def main():
    msg = [
        'Hey __receiver__,',
        'I\'m __sender_name__, a fellow Stanford student studying computer science. I\'m working on an intense class project where we interview professionals to find needs and problems in industries, and later build software solutions for free.',
        'We\'re trying our best to learn more about different industries out there.',
        'It\'d be great to hear about advice, your biggest pain points, and what\'s generally on your mind in regards to your industy. Maybe we can build something together!\n\nWould you have any time to chat on phone? Email is also great too!',
        'Thanks so much,',
        '__sender_name__'
        ]

    subject = "Test Subject Line"

    emailer = Emailer(email_body=msg, subject_line=subject, sender_name="Kevin", contacts_file = "test.txt", \
        path_to_driver="/Users/KevinYang/Documents/chromedriver")
    
    emailer.custom_login()
    emailer.send_emails()

if __name__ == "__main__":
    main()











import time
import random
import json
import sys
import csv
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from random import randint


# Make sure requirements are installed using: pip install -r requirements.txt

# JSON contacts file should look like this: [{"emails":["<EMAIL>"],"name":"James"},\
#   {"emails":["<EMAIL>"],"name":"Kevin"},{"emails":["<EMAIL>"],"name":"Will"}] 

class Emailer:
    """ This class leverages gmail to send emails to many contacts at once
    
    How to Use

        from emailer import Emailer  

        msg = [
        'Hey __receiver__,',
        'I\'m __sender_name__, a fellow Stanford student studying computer science. I\'m working on an intense class project where we interview professionals to find needs and problems in industries, and later build software solutions for free.',
        'We\'re trying our best to learn more about different industries out there.',
        'It\'d be great to hear about advice, your biggest pain points, and what\'s generally on your mind in regards to your industy. Maybe we can build something together!\n\nWould you have any time to chat on phone? Email is also great too!',
        'Thanks so much,',
        '__sender_name__'
        ]

        subject = "Test Subject Line"

        emailer = Emailer(email_body=msg, subject_line=subject, sender_name="Kevin", contacts_file = "test.txt", \
            path_to_driver="/Users/KevinYang/Documents/chromedriver")

        emailer.custom_login()
        emailer.send_emails()
    """
    def __init__(self, contacts_file, cc=[], file_type='JSON', username_email="__None__", password="__<PASSWORD>", \
        email_body="__Default_Email_Body__", subject_line="__Default_Subject_Line__", \
        sender_name = "__Default_Sender_Name__", path_to_driver = "No Path Specified"):
        """
            The parameters are as follows

            contacts_file - name of the json file. Example- chevron.txt
            file_type- the type of file that contacts_file is. Currently only JSON is supported
            username_email- gmail email used to auto login if so desired (Required for auto_login)
            password- gmail password used to auto login if so desired (Required for auto_login)
            email_body - an array of lines that will be joined with \n\n later. Example
                [
                'Hey __receiver__,',
                'I\'m __sender_name__, a fellow Stanford student studying computer science. I\'m working on an intense 
                class project where we interview professionals to find needs and problems in industries, and later 
                build software solutions for free.',
                '__misc__',
                'I would love to be able to talk to you!',
                'Thanks so much,',
                '__sender_name__'
                ]

            subject_line - subject line
            sender_name - The name of the person who is sending the email.
            path_to_driver - Path to chrome driver (Required to work)
        """
        self.file_name = contacts_file
        if(self.file_name.rsplit(".",1)[-1]=="csv"):
            file_type = 'CSV'

        self.contacts = []
        if file_type == 'JSON':
            self.file_type = 'JSON'
            try:
                print(contacts_file)
                with open(contacts_file) as json_data:
                    contacts = json.load(json_data)

                self.contacts = []
                for name in contacts: 
                    self.contacts.append({
                        'name': name,
                        'emails': [contacts[name]]
                    })

            except:
                print("Error reading in JSON file", sys.exc_info()[0])

        elif file_type == 'CSV':
            try:
                self.read_csv()
            except:
                print("Failed reading in CSV file", sys.exc_info()[0])

        self.username_email = username_email
        self.password = password

        self.driver = webdriver.Chrome(path_to_driver)

        self.subject_line = subject_line
        self.email_body = email_body
        self.sender_name = sender_name
        self.cc = cc

    # Reads in contacts from a CSV file. Look at the provided example for a sample.
    def read_csv(self):
        with open(self.file_name, 'r') as csvfile:
            reader = csv.DictReader(csvfile)
            for row in reader:
                self.contacts.append({"name":row['name'], "emails":row['emails'].split(",")})

    # Login to custom email. You need to type in your own information and login
    # You have timeout_time seconds to login before timeout
    def custom_login(self):
        self.driver.get("https://mail.google.com/?ui=html")
        timeout_time = 60
        print("You have {0} seconds to login".format(str(timeout_time)))
        try:
            element = WebDriverWait(self.driver, timeout_time).until(
                EC.title_contains("-")
            )
        finally: 
            print("Gmail loaded and ready")
            self.driver.get("https://mail.google.com/?ui=html")

    # Sends one email to email_address with subject and body and cc 
    def send_email(self, email_addresses, subject, body, cc):
        print("Sending emails to {} contacts.".format(len(self.contacts)))

        try:
            element = WebDriverWait(self.driver, 20).until(
                EC.title_contains("- Inbox")
            )
        finally: 
            print("Gmail loaded and ready")

        compose = self.driver.find_element_by_xpath("/html/body/table[2]/tbody/tr/td[1]/table[1]/tbody/tr[1]/td/b/a")
        compose.click()
        
        try:
            element = WebDriverWait(self.driver, 20).until(
                EC.visibility_of_element_located((By.ID, "to"))
            )
        finally: 
            print("Compose page loaded and ready")

        to_area = self.driver.find_element_by_id("to")

        for email in email_addresses:
            # workaround for formatting issue when downloading emails saved to airtable
            to_area.send_keys(email.replace("\'","").replace("[","").replace("]",""))
            to_area.send_keys(", ")

        cc_area = self.driver.find_element_by_id("cc")
        for email in cc:
            cc_area.send_keys(email)
            cc_area.send_keys(", ")

        subject_area = self.driver.find_element_by_xpath("/html/body/table[2]/tbody/tr/td[2]/table[1]/tbody/tr/td[2]/form/table[2]/tbody/tr[4]/td[2]/input")
        subject_area.send_keys(subject)

        # called 
        self.writeBodyText(self.email_body)

        send_button = self.driver.find_element_by_xpath("/html/body/table[2]/tbody/tr/td[2]/table[1]/tbody/tr/td[2]/form/table[1]/tbody/tr/td/input[1]")

        # Wait random number of milliseconds before sending
        time.sleep(random.uniform(0, 1))
        send_button.click()
    
    # Returns a template email. 
    def email_template(self, receiver="__None__", misc="__None__", clean_receiver=False):
        if clean_receiver:
            receiver = receiver.replace('Ms.', '').replace('Mr.', '').replace('Dr.', '').strip().split(' ')[0]
        
        msg = self.email_body

        msg = '\n\n'.join(msg)
        msg = msg.replace("__receiver__", receiver.split(" ")[0])
        msg = msg.replace("__sender_name__", self.sender_name)
        msg = msg.replace("__misc__", misc)

        return msg

    # Automatically logs in 
    def auto_login(self):
        if self.username_email == "__None__" or self.password == "__<PASSWORD>__":
            print("auto_login requires a username_email and a password." \
                " Make sure to provide both during instantiation.")
            exit()

        print("auto_login is not recommended. Be wary, as your password will be in plaintext")

        self.driver.get("https://mail.google.com/?ui=html")

        emailid=self.driver.find_element_by_id("identifierId")
        emailid.send_keys(self.username_email)

        next_button = self.driver.find_element_by_id('identifierNext')
        next_button.click()
        try:
            element = WebDriverWait(self.driver, 5).until(
                EC.visibility_of_element_located((By.ID, "password"))
            )
        finally: 
            print("Password page loaded")

        password = self.driver.find_element_by_id("password").find_element_by_tag_name("input")
        password.send_keys(<PASSWORD>)
        sign_in = self.driver.find_element_by_id("passwordNext")
        sign_in.click()

        try:
            element = WebDriverWait(self.driver, 2).until(
                EC.title_contains("Do you really want to use HTML Gmail?")
            )
        except:
            print("Simple HTML page not shown.")
        else:
            confirm_html = self.driver.find_element_by_css_selector("input[type='submit']")
            confirm_html.click()

        try:
            element = WebDriverWait(self.driver, 20).until(
                EC.title_contains("Gmail - Inbox")
            )
        finally: 
            print("Gmail loaded and ready")
            self.driver.get("https://mail.google.com/?ui=html")

    def send_emails(self):
        print("Sending emails...")
        for contact in self.contacts:
            time.sleep(randint(1,5)*0.6)
            if len(contact['emails'])==0: continue
            
            if 'misc' in contact:
                misc = contact['misc']
            else:
                misc = "__None__"
            if 'name' in contact:
                receiver = contact['name']
            else:
                receiver = "__None__"

            self.receiver = receiver
            self.misc = misc
            mail_temp = self.email_template(receiver=receiver,misc=misc)

            self.send_email(contact['emails'], self.subject_line, mail_temp, self.cc)
            print("Email sent to {0} at {1}".format(contact['name'],str(contact['emails'])))

    def writeBodyText(self, email_body):
        for line in email_body:
            line = line.replace("__receiver__", self.receiver.split(" ")[0])
            line = line.replace("__sender_name__", self.sender_name)
            line = line.replace("__misc__", self.misc)

            self.driver.execute_script('''
                document.evaluate(
                    '/html/body/table[2]/tbody/tr/td[2]/table[1]/tbody/tr/td[2]/form/table[2]/tbody/tr[8]/td[2]/textarea',  
                    document
                ).iterateNext().value += '{}';
            '''.format(line))
            
            body_area = self.driver.find_element_by_xpath("/html/body/table[2]/tbody/tr/td[2]/table[1]/tbody/tr/td[2]/form/table[2]/tbody/tr[8]/td[2]/textarea")
            body_area.send_keys('\n\n')



# ---------------------------------------------------------- #
def main():
    msg = [
        'Hey __receiver__,',
        'I\'m __sender_name__, a fellow Stanford student studying computer science. I\'m working on an intense class project where we interview professionals to find needs and problems in industries, and later build software solutions for free.',
        'We\'re trying our best to learn more about different industries out there.',
        'It\'d be great to hear about advice, your biggest pain points, and what\'s generally on your mind in regards to your industy. Maybe we can build something together!\n\nWould you have any time to chat on phone? Email is also great too!',
        'Thanks so much,',
        '__sender_name__'
        ]

    subject = "Test Subject Line"

    emailer = Emailer(email_body=msg, subject_line=subject, sender_name="Kevin", contacts_file = "test.txt", \
        path_to_driver="/Users/KevinYang/Documents/chromedriver")
    
    emailer.custom_login()
    emailer.send_emails()

if __name__ == "__main__":
    main()
# Make sure requirements are installed using: pip install -r requirements.txt # JSON contacts file should look like this: [{"emails":["<EMAIL>"],"name":"James"},\ #   {"emails":["<EMAIL>"],"name":"Kevin"},{"emails":["<EMAIL>"],"name":"Will"}] This class leverages gmail to send emails to many contacts at once          How to Use          from emailer import Emailer            msg = [         'Hey __receiver__,',         'I\'m __sender_name__, a fellow Stanford student studying computer science. I\'m working on an intense class project where we interview professionals to find needs and problems in industries, and later build software solutions for free.',         'We\'re trying our best to learn more about different industries out there.',         'It\'d be great to hear about advice, your biggest pain points, and what\'s generally on your mind in regards to your industy. Maybe we can build something together!\n\nWould you have any time to chat on phone? Email is also great too!',         'Thanks so much,',         '__sender_name__'         ]          subject = "Test Subject Line"          emailer = Emailer(email_body=msg, subject_line=subject, sender_name="Kevin", contacts_file = "test.txt", \             path_to_driver="/Users/KevinYang/Documents/chromedriver")          emailer.custom_login()         emailer.send_emails() The parameters are as follows              contacts_file - name of the json file. Example- chevron.txt             file_type- the type of file that contacts_file is. Currently only JSON is supported             username_email- gmail email used to auto login if so desired (Required for auto_login)             password- gmail password used to auto login if so desired (Required for auto_login)             email_body - an array of lines that will be joined with \n\n later. Example                 [                 'Hey __receiver__,',                 'I\'m __sender_name__, a fellow Stanford student studying computer science. I\'m working on an intense                  class project where we interview professionals to find needs and problems in industries, and later                  build software solutions for free.',                 '__misc__',                 'I would love to be able to talk to you!',                 'Thanks so much,',                 '__sender_name__'                 ]              subject_line - subject line             sender_name - The name of the person who is sending the email.             path_to_driver - Path to chrome driver (Required to work) # Reads in contacts from a CSV file. Look at the provided example for a sample. # Login to custom email. You need to type in your own information and login # You have timeout_time seconds to login before timeout # Sends one email to email_address with subject and body and cc # workaround for formatting issue when downloading emails saved to airtable # called # Wait random number of milliseconds before sending # Returns a template email. # Automatically logs in document.evaluate(                     '/html/body/table[2]/tbody/tr/td[2]/table[1]/tbody/tr/td[2]/form/table[2]/tbody/tr[8]/td[2]/textarea',                       document                 ).iterateNext().value += '{}'; # ---------------------------------------------------------- #