From ad82558be2a4911b9acf2484e9097b3831863350 Mon Sep 17 00:00:00 2001 From: Kevin Patel Date: Sun, 16 Aug 2020 12:42:09 +1000 Subject: [PATCH 1/2] Added python email client --- .../Email_Client/README.md | 2 + .../Email_Client/email_client.py | 189 ++++++++++++++++++ .../Email_Client/email_client_test.py | 111 ++++++++++ .../Email_Client/password.txt | 1 + .../Email_Client/test.txt | 0 5 files changed, 303 insertions(+) create mode 100644 System-Automation-Scripts/Email_Client/README.md create mode 100644 System-Automation-Scripts/Email_Client/email_client.py create mode 100644 System-Automation-Scripts/Email_Client/email_client_test.py create mode 100644 System-Automation-Scripts/Email_Client/password.txt create mode 100644 System-Automation-Scripts/Email_Client/test.txt diff --git a/System-Automation-Scripts/Email_Client/README.md b/System-Automation-Scripts/Email_Client/README.md new file mode 100644 index 00000000..e4500575 --- /dev/null +++ b/System-Automation-Scripts/Email_Client/README.md @@ -0,0 +1,2 @@ +# Email Client using Python for automating email shooting process +Python email client that can be used to automate email sending process. \ No newline at end of file diff --git a/System-Automation-Scripts/Email_Client/email_client.py b/System-Automation-Scripts/Email_Client/email_client.py new file mode 100644 index 00000000..e0d8cd3a --- /dev/null +++ b/System-Automation-Scripts/Email_Client/email_client.py @@ -0,0 +1,189 @@ +import os +import smtplib +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +from email.mime.base import MIMEBase +from email.utils import formatdate +from email import encoders +from pathlib import Path + + +class EmailClient: + """ An email client to send emails. + """ + + def __init__(self, server: str, server_port: int, user_name: str, password: str): + """ Class constructor to initialise EmailClient + + Parameters: + server (str): Email server used by the user + server_port (int): Port number of the email server + user_name (str): Email address + password (str): Email password + """ + + # Email credentials + self.user_name = user_name + self.__password = password + + # used to add plain texts/HTML parts in the email + self.__email_content = MIMEMultipart() + # add sender's info + self.__email_content['From'] = user_name + # uses SMTP email protocol to communicate with email service provider + self.__mail_server = smtplib.SMTP( + host=server, port=server_port) + + # necessary for internal workings + self.__is_subject_added = False + self.__is_body_added = False + self.__is_attached = False + self.__is_signature_added = False + + def set_subject(self, subject: str): + """ Method to set subject for the email (optional). + + Parameters: + subject (str): Email subject to set + """ + + self.__is_subject_added = (subject is not None and subject != '') + if self.__is_subject_added: + self.__email_content['Subject'] = subject + + def set_body(self, body: str): + """ Method to set body for the email (optional). + + Parameters: + body (str): Email body to set + """ + + self.__is_body_added = (body is not None and body != '') + if self.__is_body_added: + self.__email_content.attach(MIMEText(body, 'plain')) + + def set_signature(self, signature: str): + """ Method to set signature for the email (optional). + + Parameters: + signature (str): Email signature to set + """ + + self.__is_signature_added = (signature is not None and signature != '') + if self.__is_signature_added: + self.__email_content.attach(MIMEText(signature, 'plain')) + + def add_attachment(self, attachment_path: str): + """ Method to attach attachments in the email (optional). + + Parameters: + attachment_path (str): Path of attachment + """ + + attachment = MIMEBase('application', "octet-stream") + + with open(attachment_path, 'rb') as file: + attachment.set_payload(file.read()) + + encoders.encode_base64(attachment) + attachment.add_header('Content-Disposition', + 'attachment; filename="{}"'.format(Path(attachment_path).name)) + + self.__email_content.attach(attachment) + + # added attachment + self.__is_attached = True + + def send(self, recipient: str) -> bool: + """ Method to send email message. + + Parameters: + recipient (str): Recipient's email address + + Returns: + bool: Determines success of email being sent + """ + if self.__is_attached and not self.__is_subject_added: + print('Error: Subject is empty. Please add a subject and send again.') + return False + + if not self.__is_subject_added and not self.__is_body_added and not self.__is_signature_added: + print('Error: Cannot send empty email message. Please add at least one from subject, body or signature.') + return False + + self.__email_content['To'] = recipient + self.__email_content['Date'] = formatdate(localtime=True) + + try: + self.__mail_server.starttls() # start a secure TLS connection + # login with user credentials on email server + self.__mail_server.login(self.user_name, self.__password) + + # send email message + self.__mail_server.send_message(self.__email_content) + + return True + except Exception as e: + print('Something went wrong :(\n', e) + + return False + finally: + # close connection with email server + self.__mail_server.quit() + + def reset_email(self): + """ Resets all email content except for the initialisation details. + """ + + # used to add plain texts/HTML parts in the email + self.__email_content = MIMEMultipart() + # add sender's info + self.__email_content['From'] = self.user_name + + # necessary for internal workings + self.__is_subject_added = False + self.__is_body_added = False + self.__is_attached = False + self.__is_signature_added = False + + +# driver code +if __name__ == "__main__": + + # NOTE: if you're using Gmail account for sending email, you may have to turn off one of Google account's setting. + # link: https://myaccount.google.com/lesssecureapps + # More about this issue: https://stackoverflow.com/questions/16512592/login-credentials-not-working-with-gmail-smtp + + # using Google mail server + mail_server = 'smtp.gmail.com' + port_number = 587 + # sender's credentials + username = 'sender@email.com' # enter your gmail address + with open('password.txt', 'r') as pass_file: + email_password = pass_file.read() + # recipient's email address + email_recipient = 'recipient@email.com' # enter sender's email address + + # Email message content + # Email subject + email_subject = 'Hello, world!' + + # Email body + email_body = 'Hello there, \n\nThis is my automated email. Please do not reply.' + + # Email signature + email_signature = '\n\nKind regards,\n{}'.format(username) + + # using 'EmailClient' class for sending email messages + email_client = EmailClient( + mail_server, port_number, username, email_password) + email_client.set_subject(email_subject) + email_client.set_body(email_body) + email_client.set_signature(email_signature) + # email_client.add_attachment('file_to_attach.txt') + + # sending email + if email_client.send(email_recipient): + print('Email sent.') + else: + print('Failed :(') diff --git a/System-Automation-Scripts/Email_Client/email_client_test.py b/System-Automation-Scripts/Email_Client/email_client_test.py new file mode 100644 index 00000000..56266a6c --- /dev/null +++ b/System-Automation-Scripts/Email_Client/email_client_test.py @@ -0,0 +1,111 @@ +from email_client import EmailClient +import unittest + + +class EmailClientTest(unittest.TestCase): + """ Tests for EmailClient class + """ + + # credentials + # using Google mail server + __server = 'smtp.gmail.com' + __port_number = 587 + # sender's credentials + __username = 'sender@gmail.com' + with open('password.txt', 'r') as pass_file: + __password = pass_file.read() + # recipient's email addr + __recipient = 'recipient@email.com' + + # test case #1 - testing sending functionality of EmailClient class + def test_email_client_send(self): + # Email message content + # Email subject + subject = 'Testing' + # Email body + body = 'Hi,\n\nI am Kevin. How are you?' + # Email signature + signature = '\n\nKind regards,\n{}'.format(self.__username) + + # sending Email + email_client = EmailClient( + self.__server, self.__port_number, self.__username, self.__password) + email_client.set_subject(subject) + email_client.set_body(body) + email_client.set_signature(signature) + email_client.add_attachment('test.txt') + + # testing + sent = True + self.assertEqual(email_client.send(self.__recipient), sent) + + # test case #2 - EmailClient Should not send empty emails + def test_empty_email(self): + # Empty Email message content + # Email subject + subject = '' + # Email body + body = '' + # Email signature + signature = '' + + # sending Email + email_client = EmailClient( + self.__server, self.__port_number, self.__username, self.__password) + email_client.set_subject(subject) + email_client.set_body(body) + email_client.set_signature(signature) + + # testing + sent = False + self.assertEqual(email_client.send(self.__recipient), sent) + + # test case #3 - testing reset functionality in EmailClient class + def test_email_client_reset(self): + # Email message content + # Email subject + subject = 'Testing Reset Method' + # Email body + body = 'Email body has not been reset. Please check its functionality.' + # Email signature + signature = '\n\nKind regards,\nkevinmanojpatel@gmail.com' + + # initialising Email + email_client = EmailClient( + self.__server, self.__port_number, self.__username, self.__password) + email_client.set_subject(subject) + email_client.set_body(body) + email_client.set_signature(signature) + email_client.add_attachment('test.txt') + + # resetting email content + email_client.reset_email() + + # adding Email body + new_body = 'Email body has been reset.' + email_client.set_body(new_body) + + # testing + sent = True + self.assertEqual(email_client.send(self.__recipient), sent) + + # test case #4 - testing sending functionality when special case of attachment added but not subject + def test_email_client_send_misc(self): + # Email message content + # Email subject + subject = '' + + # sending Email + email_client = EmailClient( + self.__server, self.__port_number, self.__username, self.__password) + email_client.set_subject(subject) + # add Email attachment + email_client.add_attachment('test.txt') + + # testing + sent = False + self.assertEqual(email_client.send(self.__recipient), sent) + + +if __name__ == '__main__': + unittest.main() # running tests on EmailClient diff --git a/System-Automation-Scripts/Email_Client/password.txt b/System-Automation-Scripts/Email_Client/password.txt new file mode 100644 index 00000000..9c16badb --- /dev/null +++ b/System-Automation-Scripts/Email_Client/password.txt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/System-Automation-Scripts/Email_Client/test.txt b/System-Automation-Scripts/Email_Client/test.txt new file mode 100644 index 00000000..e69de29b From 56aead0e606882f4479447b6d5b8c275cee417d3 Mon Sep 17 00:00:00 2001 From: Kevin Patel <42174390+PatelKeviin@users.noreply.github.com> Date: Tue, 18 Aug 2020 12:34:29 +1000 Subject: [PATCH 2/2] Update README.md file --- System-Automation-Scripts/Email_Client/README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/System-Automation-Scripts/Email_Client/README.md b/System-Automation-Scripts/Email_Client/README.md index e4500575..326420c8 100644 --- a/System-Automation-Scripts/Email_Client/README.md +++ b/System-Automation-Scripts/Email_Client/README.md @@ -1,2 +1,14 @@ # Email Client using Python for automating email shooting process -Python email client that can be used to automate email sending process. \ No newline at end of file +Python email client that can be used to automate email sending process. + +## Pre-requisites :rotating_light: +[![GitHub top language](https://img.shields.io/github/languages/top/vinitshahdeo/PortScanner?logo=python&logoColor=white)](https://www.python.org/) +- **Python** `>= v3.7.x` + - Install Python from [here](https://www.python.org/). +- **Pip** `>= v20.0.x` + - Install pip from [here](https://pip.pypa.io/en/stable/installing/). + +## How to run? :rocket: +### To run Email Client: (Via Terminal) +- Update `email_client.py` file to enter Email credentials for the sender account as well as the recipient's address. +- **Open terminal** and type **`python Email_CLient/email_client.py`**.