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

Added python email client script #101

Merged
merged 2 commits into from
Aug 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link

@Neilblaze Neilblaze Aug 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will recommend you to elaborate the installation process briefly along with what's already present in README file.

Rest, LGTM 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Neilblaze, I have updated the changes as advised. Also, thank you very much for your kind words!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Neilblaze as all the required modules are part of Python Standard Libraries, nothing in particular is required in terms of set-up as long as the user has Python installed on his/her machine :)

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,\[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.