Skip to content
This repository has been archived by the owner on Nov 30, 2022. It is now read-only.

Commit

Permalink
Merge pull request #101 from PatelKeviin/email-client-issue94
Browse files Browse the repository at this point in the history
Added python email client script
  • Loading branch information
powerexploit authored Aug 20, 2020
2 parents bc5cce3 + 56aead0 commit 2f5727f
Show file tree
Hide file tree
Showing 5 changed files with 315 additions and 0 deletions.
14 changes: 14 additions & 0 deletions System-Automation-Scripts/Email_Client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Email Client using Python for automating email shooting process
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`**.
189 changes: 189 additions & 0 deletions System-Automation-Scripts/Email_Client/email_client.py
Original file line number Diff line number Diff line change
@@ -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 = '[email protected]' # enter your gmail address
with open('password.txt', 'r') as pass_file:
email_password = pass_file.read()
# recipient's email address
email_recipient = '[email protected]' # 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 :(')
111 changes: 111 additions & 0 deletions System-Automation-Scripts/Email_Client/email_client_test.py
Original file line number Diff line number Diff line change
@@ -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 = '[email protected]'
with open('password.txt', 'r') as pass_file:
__password = pass_file.read()
# recipient's email addr
__recipient = '[email protected]'

# 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,\n[email protected]'

# 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
1 change: 1 addition & 0 deletions System-Automation-Scripts/Email_Client/password.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<your password>
Empty file.

0 comments on commit 2f5727f

Please sign in to comment.