diff --git a/README.md b/README.md index 0a2c85f..4ca3243 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ else: receiver: Email Address as String or List. [Recuired] cc: Email Address as String or List. (Carbon Copy) [Optional] bcc: Email Address as String or List. (Blind Carbon Copy) [Optional] +no_reply: Set Another Email To Reoly [Optional] subject: Message Title. [Optional] message: Your Message. [Optional] image: Image File Name. (Image Path) [Optional] diff --git a/dist/quick-mailer-2022.1.19.tar.gz b/dist/quick-mailer-2022.1.19.tar.gz new file mode 100644 index 0000000..eee3cd5 Binary files /dev/null and b/dist/quick-mailer-2022.1.19.tar.gz differ diff --git a/dist/quick_mailer-2022.1.19-py3-none-any.whl b/dist/quick_mailer-2022.1.19-py3-none-any.whl new file mode 100644 index 0000000..a9682ac Binary files /dev/null and b/dist/quick_mailer-2022.1.19-py3-none-any.whl differ diff --git a/mailer/__init__.py b/mailer/__init__.py index eff6769..b771c24 100644 --- a/mailer/__init__.py +++ b/mailer/__init__.py @@ -22,305 +22,8 @@ SOFTWARE. """ -import ssl as _ssl -from email.mime.application import MIMEApplication as _MIMEApp -from email.mime.audio import MIMEAudio as _MIMEAudio -from email.mime.image import MIMEImage as _MIMEImage -from email.mime.multipart import MIMEMultipart as _MIMEMultipart -from email.mime.text import MIMEText as _MIMEText -from smtplib import SMTP as _SMTP -from time import sleep as _sleep +from mailer.mailer import Mailer +from mailer.utils import example __all__ = ['Mailer', '__VERSION__', 'example'] -__VERSION__ = '0.1.0' - - -# Main Class -class Mailer: - def __init__(self, email: str, password: str): - """ - :param email: Your Email Address - :param password: Yor Email Password - """ - # Variables - self.email = email - self.__password = password - self.__server = None - self.status = bool() - self.login = bool() - self.multi = bool() - self.__sleep = int() - self.__repeat = 1 - self.count_rec = 1 - self.count_cc = int() - self.count_bcc = int() - self.count_msg = self.__repeat*self.count_rec - self.__port = 587 - self.GMAIL = 'smtp.gmail.com' - # self.YAHOO = 'smtp.mail.yahoo.com' # Unsupported Now - self.MICROSOFT = 'smtp.office365.com' - self.provider = self.GMAIL - - # Apply Settings - self.settings() - - # About Method - @staticmethod - def about(): - info = """ -About Module: - This Module help you to send fast Email. - And you can attach [image, audio, and other files] easily. - -About Developer: - Name: Ahmed Al-Taie - Github: https://github.com/Al-Taie - Pypi: https://pypi.org/user/Altaie - Instagram: https://www.instagram.com/9_Tay - - Finally Thanks For Use My Module. - You Can Join Our Discord For Any Question: - Discord: https://discord.gg/gWdCNv7 - """ - print(info) - return - - # File Reader Method - @staticmethod - def _file_reader(filename: str): - with open(filename, 'rb') as f: - return f.read() - - # Settings Method - def settings(self, - repeat: int = 1, - sleep=None, - provider: str = None, - multi=False): - """ - :param multi: - :type multi: - :param repeat: Repeat Number - :param sleep: Set Sleep Time (In Seconds) - :param provider: See example Function - :return: None - """ - self.__repeat = repeat - self.multi = multi - - if sleep: - self.__sleep = sleep - - if provider: - self.provider = provider - - # Login Method - def __login(self): - context = _ssl.create_default_context() - - self.__server = _SMTP(host=self.provider, - port=self.__port) - self.__server.ehlo() - self.__server.starttls(context=context) - self.__server.ehlo() - - try: - self.__server.login(user=self.email, - password=self.__password) - self.login = True - return True - except Exception as e: - if self.provider == self.GMAIL: - problem = """ -Error: Email And Password Not Accepted. - -Note: - Make sure you Allowed less secure apps, - if you didn't, visit this link: - ==> https://myaccount.google.com/lesssecureapps - - For More information visit this link: - ==> https://support.google.com/mail/?p=BadCredentials - """ - else: - problem = e - print(problem) - self.login = False - return False - - # Send Method - def send(self, - receiver, - cc=None, - bcc=None, - subject: str = None, - message: str = None, - image: str = None, - audio: str = None, - file: str = None): - """ - :param cc: Email Address as String or List. (Carbon Copy) - :param bcc: Email Address as String or List. (Blind Carbon Copy) - :param receiver: Email Address as String or List - :param subject: Message Title - :param message: Your Message - :param image: Image File Name - :param audio: Audio File Name - :param file: File Name - :return: Boolean - """ - - msg = _MIMEMultipart() - msg['Subject'] = subject - msg['From'] = self.email - - try: - if message is not None: - text = _MIMEText(message) - msg.attach(text) - - if image is not None: - image_data = self._file_reader(image) - image = _MIMEImage(_imagedata=image_data, name=image) - msg.attach(image) - - if audio is not None: - audio_data = self._file_reader(audio) - audio = _MIMEAudio(_audiodata=audio_data, name=audio, _subtype='') - msg.attach(audio) - - if file is not None: - file_data = self._file_reader(file) - file = _MIMEApp(_data=file_data, name=file) - msg.attach(file) - except Exception: - print('Error: File Not Found!') - self.status = False - return False - - send_info = [] - multi_info = {} - - if 'list' in str(type(receiver)): - self.count_rec = len(receiver) - receiver = ','.join(i for i in receiver) - - if 'list' in str(type(cc)): - self.count_cc = len(cc) - cc = ','.join(i for i in cc) - - if 'list' in str(type(bcc)): - self.count_bcc = len(bcc) - bcc = ','.join(i for i in bcc) - - if self.__login(): - msg['To'] = receiver - msg['CC'] = cc - msg['BCC'] = bcc - - if self.multi: - for _ in range(self.__repeat): - try: - self.__server.sendmail(from_addr=self.email, - to_addrs=receiver, - msg=msg.as_string()) - except Exception: - if self.__repeat == 1 & self.count_rec == 1: - self.status = False - else: - send_info.append(False) - - else: - if self.__repeat == 1 & self.count_rec == 1: - self.status = True - else: - send_info.append(True) - self.status = send_info - - finally: - _sleep(self.__sleep) - else: - for rec in receiver.split(','): - send_info = [] - for _ in range(self.__repeat): - try: - self.__server.sendmail(from_addr=self.email, - to_addrs=rec, - msg=msg.as_string()) - except Exception as e: - if self.__repeat == 1 & self.count_rec == 1: - self.status = False - else: - send_info.append(False) - - if 'OutboundSpamException' in str(e): - print('Error: Please Login To Your Account And Verify it.') - break - - else: - if self.__repeat == 1 & self.count_rec == 1: - self.status = True - else: - send_info.append(True) - self.status = send_info - multi_info[rec] = send_info - - finally: - _sleep(self.__sleep) - - if self.count_rec != 1: - self.status = multi_info - - self.__server.close() - - -# Example Function -def example(): - ex = """ -#################### -# [Copy This Code] # -#################### - -mail = Mailer(email='someone@gmail.com', - password='***') - -# IF You Want Repeat Sending, Change repeat Value -# And IF You Want Change Mail Service -# Chose One: mail.[GMAIL, MICROSOFT] -mail.settings(repeat=1, - sleep=0, - provider=mail.GMAIL, - multi=False) - -# Send Message -mail.send(receiver='someone@example.com', # Email From Any service Provider - cc='someone1@example.com' - bcc='someone2@example.com' - subject='TEST', - message='HI, This Message From Python :)', - image=None, # Image File Path - audio=None, # Audio File Path - file=None) # Any File Path - -# Login Status Info -print('login:', mail.login) - -# Sending Status Info -print('status:', mail.status) - -# CC Receivers Count -print('CC count:', mail.count_cc) - -# BCC Receivers Count -print('BCC count:', mail.count_bcc) - -# Receivers Count -print('Receivers count:', mail.count_rec) - -# Messages Count IF You Allowed Repeat -print('Messages count:', mail.count_msg) - -# For More Information -mail.about() - """ - print(ex) +__VERSION__ = '2022.1.19' diff --git a/mailer/exceptions.py b/mailer/exceptions.py new file mode 100644 index 0000000..d1bd504 --- /dev/null +++ b/mailer/exceptions.py @@ -0,0 +1,34 @@ +class ImageNotFoundError(FileNotFoundError): + """Exception raised when image not exists. + + Attributes: + message -- explanation of the error + """ + + def __init__(self, message="Image not exists in a path!"): + self.message = message + super().__init__(self.message) + + +class AudioNotFoundError(FileNotFoundError): + """Exception raised when audio not exists. + + Attributes: + message -- explanation of the error + """ + + def __init__(self, message="Audio not exists in a path!"): + self.message = message + super().__init__(self.message) + + +class OutboundSpamException(Exception): + """Exception raised when Account need to verify. + + Attributes: + message -- explanation of the error + """ + + def __init__(self, message="Please Login To Your Account And Verify it."): + self.message = message + super().__init__(self.message) diff --git a/mailer/login.py b/mailer/login.py new file mode 100644 index 0000000..f6271a5 --- /dev/null +++ b/mailer/login.py @@ -0,0 +1,62 @@ +import ssl as _ssl +from smtplib import SMTP as _SMTP + + +class Login: + def __init__(self, email: str, password: str): + """ + :param email: Your Email Address + :param password: Yor Email Password + """ + # Variables + self.email = email + self.__password = password + self._server = None + self.status = bool() + self.login = bool() + self.multi = bool() + self._sleep = int() + self._repeat = 1 + self.count_rec = 1 + self.count_cc = int() + self.count_bcc = int() + self.count_msg = self._repeat * self.count_rec + self.__port = 587 + self.GMAIL = 'smtp.gmail.com' + # self.YAHOO = 'smtp.mail.yahoo.com' # Unsupported Now + self.MICROSOFT = 'smtp.office365.com' + self.provider = self.GMAIL + + # Login Method + def _login(self) -> bool: + context = _ssl.create_default_context() + + self._server = _SMTP(host=self.provider, + port=self.__port) + self._server.ehlo() + self._server.starttls(context=context) + self._server.ehlo() + + try: + self._server.login(user=self.email, + password=self.__password) + self.login = True + return True + except Exception as e: + if self.provider == self.GMAIL: + problem = """ +Error: Email And Password Not Accepted. + +Note: + Make sure you Allowed less secure apps, + if you didn't, visit this link: + ==> https://myaccount.google.com/lesssecureapps + + For More information visit this link: + ==> https://support.google.com/mail/?p=BadCredentials + """ + else: + problem = e + print(problem) + self.login = False + return False diff --git a/mailer/mailer.py b/mailer/mailer.py new file mode 100644 index 0000000..77ef8eb --- /dev/null +++ b/mailer/mailer.py @@ -0,0 +1,59 @@ +from typing import Text + +from mailer.send import Send + + +class Mailer(Send): + def __init__(self, email: str, password: str): + """ + :param email: Your Email Address + :param password: Yor Email Password + """ + # Variables + super().__init__(email=email, password=password) + # Apply Settings + self.settings() + + # About Method + @staticmethod + def about() -> Text: + info = """ +About Module: + This Module help you to send fast Email. + And you can attach [image, audio, and other files] easily. + +About Developer: + Name: Ahmed Al-Taie + Github: https://github.com/Al-Taie + Pypi: https://pypi.org/user/Altaie + Instagram: https://www.instagram.com/9_Tay + + Finally Thanks For Use My Module. + You Can Join Our Discord For Any Question: + Discord: https://discord.gg/gWdCNv7 + """ + print(info) + return info + + # Settings Method + def settings(self, + repeat: int = 1, + sleep=None, + provider: str = None, + multi=False) -> None: + """ + :param multi: + :type multi: + :param repeat: Repeat Number + :param sleep: Set Sleep Time (In Seconds) + :param provider: See example Function + :return: None + """ + self._repeat = repeat + self.multi = multi + + if sleep: + self._sleep = sleep + + if provider: + self.provider = provider diff --git a/mailer/send.py b/mailer/send.py new file mode 100644 index 0000000..84a9aa4 --- /dev/null +++ b/mailer/send.py @@ -0,0 +1,163 @@ +from email.mime.application import MIMEApplication as _MIMEApp +from email.mime.audio import MIMEAudio as _MIMEAudio +from email.mime.image import MIMEImage as _MIMEImage +from email.mime.multipart import MIMEMultipart as _MIMEMultipart +from email.mime.text import MIMEText as _MIMEText +from time import sleep as _sleep + +from mailer.exceptions import ImageNotFoundError, AudioNotFoundError, OutboundSpamException +from mailer.login import Login +from mailer.utils import file_reader + + +class Send(Login): + def __init__(self, email: str, password: str): + """ + :param email: Your Email Address + :param password: Yor Email Password + """ + # Variables + super().__init__(email=email, password=password) + self._msg = _MIMEMultipart() + + def __prepare_message(self, + receiver, + cc=None, + bcc=None, + no_reply: str = None, + subject: str = None, + message: str = None) -> None: + self._msg['Subject'] = subject + self._msg['From'] = self.email + + if message is not None: + text = _MIMEText(message) + self._msg.attach(text) + + if list == type(receiver): + self.count_rec = len(receiver) + receiver = ','.join(i for i in receiver) + + if list == type(cc): + self.count_cc = len(cc) + cc = ','.join(i for i in cc) + + if list == type(bcc): + self.count_bcc = len(bcc) + bcc = ','.join(i for i in bcc) + + self._msg['To'] = receiver + self._msg['CC'] = cc + self._msg['BCC'] = bcc + self._msg['Reply-To'] = no_reply + + def __prepare_attachments(self, + image: str = None, + audio: str = None, + file: str = None) -> None: + if image is not None: + image_data = file_reader(image) + # assert image_data, ImageNotFoundError() + assert image_data, ImageNotFoundError() + image = _MIMEImage(_imagedata=image_data, name=image) + self._msg.attach(image) + + if audio is not None: + audio_data = file_reader(audio) + assert audio_data, AudioNotFoundError() + audio = _MIMEAudio(_audiodata=audio_data, name=audio, _subtype='') + self._msg.attach(audio) + + if file is not None: + file_data = file_reader(file) + assert file_data, FileNotFoundError("File not exists in a path!") + file = _MIMEApp(_data=file_data, name=file) + self._msg.attach(file) + + # Send Method + def send(self, + receiver, + cc=None, + bcc=None, + no_reply: str = None, + subject: str = None, + message: str = None, + image: str = None, + audio: str = None, + file: str = None) -> None: + """ + :param no_reply: Set no-reply email + :param cc: Email Address as String or List. (Carbon Copy) + :param bcc: Email Address as String or List. (Blind Carbon Copy) + :param receiver: Email Address as String or List + :param subject: Message Title + :param message: Your Message + :param image: Image File Name + :param audio: Audio File Name + :param file: File Name + :return: Boolean + """ + + send_info = [] + multi_info = {} + + self.__prepare_message(receiver=receiver, cc=cc, + bcc=bcc, subject=subject, + message=message, no_reply=no_reply) + + self.__prepare_attachments(image=image, + audio=audio, + file=file) + if self._login(): + if self.multi: + for _ in range(self._repeat): + try: + self._server.sendmail(from_addr=self.email, + to_addrs=receiver, + msg=self._msg.as_string()) + except Exception: + if self._repeat == 1 & self.count_rec == 1: + self.status = False + else: + send_info.append(False) + + else: + if self._repeat == 1 & self.count_rec == 1: + self.status = True + else: + send_info.append(True) + self.status = send_info + + finally: + _sleep(self._sleep) + else: + for rec in receiver.split(','): + send_info = [] + for _ in range(self._repeat): + try: + self._server.sendmail(from_addr=self.email, + to_addrs=rec, + msg=self._msg.as_string()) + except Exception as e: + if self._repeat == 1 & self.count_rec == 1: + self.status = False + else: + send_info.append(False) + + assert OutboundSpamException.__name__ not in str(e), OutboundSpamException() + + else: + if self._repeat == 1 & self.count_rec == 1: + self.status = True + else: + send_info.append(True) + self.status = send_info + multi_info[rec] = send_info + + finally: + _sleep(self._sleep) + + if self.count_rec != 1: + self.status = multi_info + + self._server.close() diff --git a/mailer/utils.py b/mailer/utils.py new file mode 100644 index 0000000..8ab9041 --- /dev/null +++ b/mailer/utils.py @@ -0,0 +1,62 @@ +from typing import Text + + +def file_reader(filename: str) -> bytes | bool: + try: + with open(filename, 'rb') as f: + return f.read() + except FileNotFoundError: + return False + + +# Example Function +def example() -> Text: + ex = """ +#################### +# [Copy This Code] # +#################### + +mail = Mailer(email='someone@gmail.com', + password='***') + +# IF You Want Repeat Sending, Change repeat Value +# And IF You Want Change Mail Service +# Chose One: mail.[GMAIL, MICROSOFT] +mail.settings(repeat=1, + sleep=0, + provider=mail.GMAIL, + multi=False) + +# Send Message +mail.send(receiver='someone@example.com', # Email From Any service Provider + cc='someone1@example.com', + bcc='someone2@example.com', + subject='TEST', + message='HI, This Message From Python :)', + image=None, # Image File Path + audio=None, # Audio File Path + file=None) # Any File Path + +# Login Status Info +print('login:', mail.login) + +# Sending Status Info +print('status:', mail.status) + +# CC Receivers Count +print('CC count:', mail.count_cc) + +# BCC Receivers Count +print('BCC count:', mail.count_bcc) + +# Receivers Count +print('Receivers count:', mail.count_rec) + +# Messages Count IF You Allowed Repeat +print('Messages count:', mail.count_msg) + +# For More Information +mail.about() + """ + print(ex) + return ex diff --git a/quick_mailer.egg-info/PKG-INFO b/quick_mailer.egg-info/PKG-INFO new file mode 100644 index 0000000..2915f7b --- /dev/null +++ b/quick_mailer.egg-info/PKG-INFO @@ -0,0 +1,148 @@ +Metadata-Version: 2.1 +Name: quick-mailer +Version: 2022.1.19 +Summary: This Module help you to send fast Email.🌸 +Home-page: https://github.com/Al-Taie/quick-mailer +Author: Ahmed Al-Taie +Author-email: agprosup@gmail.com +License: UNKNOWN +Keywords: smtp,mail,gmail,email +Platform: UNKNOWN +Classifier: Programming Language :: Python :: 3 +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Description-Content-Type: text/markdown +License-File: LICENSE + +![image](images/bsmala.png) + +[![Downloads](https://pepy.tech/badge/quick-mailer)](https://pepy.tech/project/quick-mailer) +[![Downloads](https://pepy.tech/badge/quick-mailer/month)](https://pepy.tech/project/quick-mailer/month) +[![Downloads](https://pepy.tech/badge/quick-mailer/week)](https://pepy.tech/project/quick-mailer/week) + + +# Description +This Module help you to send **fast Email. 🌸** + +And you can attach **image, audio, and other files easily.** + +The Module support **Gmail And Microsoft** right now, but in the nearly future will support other mail services. + +# Installation: +```cmd +pip install quick-mailer +``` + +**[-->> pypi Link](https://pypi.org/project/quick-mailer)** + +# Usage: +**Send Message** +```py +from mailer import Mailer + +mail = Mailer(email='someone@gmail.com', + password='your_password') + +mail.send(receiver='someone@example.com', # Email From Any service Provider + subject='TEST', + message='HI, This Message From Python :)') +``` + +**Check Send Status** +```py +# Uaing (status) Variable +print(mail.status) + +# Example For One Receiver: +if mail.status: + pass +else: + pass + + # Note: + # IF You Put List Emails Receivers + # Variable Will Return Dictionary Results. + + # IF You Allowed Repeat + # Variable Will Return List Results. +``` + +**Parameters** +```py +receiver: Email Address as String or List. [Recuired] +cc: Email Address as String or List. (Carbon Copy) [Optional] +bcc: Email Address as String or List. (Blind Carbon Copy) [Optional] +no_reply: Set Another Email To Reoly [Optional] +subject: Message Title. [Optional] +message: Your Message. [Optional] +image: Image File Name. (Image Path) [Optional] +audio: Audio File Name. (Audio Path) [Optional] +file: File Name. (Any File Path) [Optional] +``` + +**Send Multi Files** +```py +mail.send(receiver='someone@example.com', # Email From Any service Provider + subject='TEST', + message='HI, This Message From Python :)', + image='img.jpg', # Image File Path + audio='sound.mp3', # Audio File Path + file='file.zip') # Any File Path +``` + +**Settings Method** +```py +mail.settings(repeat=1, # To Repeat Sending + sleep=0, # To Sleep After Send Each Message + provider=mail.GMAIL, # Set Maill Service + multi=False) # Default False, If You Set True + # Message Will Sent 4 Each Email Alone + # Else Will Sent To All Together +``` + +**Send Multi Emails** +```py +# One By One: +mail.settings(multi=False) + +# In Same Message: +mail.settings(multi=True) + +mail.send(receiver=['someone@example.com', 'someone1@example.com'], + subject='TEST', + message='HI, This Message From Python :)') +``` + +**Counter Variables** +```py +# CC Receivers Count +print('CC count:', mail.count_cc) + +# BCC Receivers Count +print('BCC count:', mail.count_bcc) + +# Receivers Count +print('Receivers count:', mail.count_rec) + +# Messages Count +print('Messages count:', mail.count_msg) +``` + +**Example Function** +```py +from mailer import example + +example() +``` + +**About Method** +```py +# You Can Use (mail.about) Method for more info. +mail.about() +``` + +**Follow Me on Instagram: [@9_Tay](https://www.instagram.com/9_tay). 🌸** + +# Thank You :) 🌸 +🌸 + diff --git a/quick_mailer.egg-info/SOURCES.txt b/quick_mailer.egg-info/SOURCES.txt new file mode 100644 index 0000000..a654aa2 --- /dev/null +++ b/quick_mailer.egg-info/SOURCES.txt @@ -0,0 +1,13 @@ +LICENSE +README.md +setup.py +mailer/__init__.py +mailer/exceptions.py +mailer/login.py +mailer/mailer.py +mailer/send.py +mailer/utils.py +quick_mailer.egg-info/PKG-INFO +quick_mailer.egg-info/SOURCES.txt +quick_mailer.egg-info/dependency_links.txt +quick_mailer.egg-info/top_level.txt \ No newline at end of file diff --git a/quick_mailer.egg-info/dependency_links.txt b/quick_mailer.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/quick_mailer.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/quick_mailer.egg-info/top_level.txt b/quick_mailer.egg-info/top_level.txt new file mode 100644 index 0000000..f2ae723 --- /dev/null +++ b/quick_mailer.egg-info/top_level.txt @@ -0,0 +1 @@ +mailer