This repository has been archived by the owner on Nov 30, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 214
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #101 from PatelKeviin/email-client-issue94
Added python email client script
- Loading branch information
Showing
5 changed files
with
315 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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`**. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
111
System-Automation-Scripts/Email_Client/email_client_test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<your password> |
Empty file.