Schedule email notification to outlook contact using Python3.6 - python-3.x

I need to send weekly email notifications to corporate contact in outlook using Python3.6
I tried smtplib but it works for gmail, doesn't work for outlook contact.
I tried win32com.client, but it is not supported by Python version < 3.8
Kindly help.

Once you take the steps below, SMTP will function:
Open Outlook in a browser; click the gear icon for Settings in the top right corner; Then select "Options" from the drop-down list that appears. You can choose to "Let devices and apps utilise pop" by going to "Accounts," clicking "Pop and Imap," and then saving your choices.
here is the code snippet:
import smtplib
body = 'Subject: Subject Here .\nDear ContactName, \n\n' + 'Email\'s BODY text' + '\nYour :: Signature/Innitials'
try:
smtpObj = smtplib.SMTP('smtp-mail.outlook.com', 587)
except Exception as e:
print(e)
smtpObj = smtplib.SMTP_SSL('smtp-mail.outlook.com', 465)
#type(smtpObj)
smtpObj.ehlo()
smtpObj.starttls()
smtpObj.login('me#outlook.com', "password")
smtpObj.sendmail('sender#outlook.com', 'recipient#outlook.com', body) # Or recipient#gmail
smtpObj.quit()

Related

Unable to save emails in DRAFT folder using Python GMAIL IMAP

I am trying to save multiple emails in my drafts folder so I could review and press the SEND button in my web browser but I seem to be running into multiple issues.
I spent about half a day checking google and stackoverflow but didnt get much luck:
Here are a few examples that seemed relevant but didnt work
How do I create a draft in Gmail using IMAP using Python
Programmatically Save Draft in Gmail drafts folder
Creating a Draft message in Gmail using the imaplib in Python
Programmatically Save Draft in Gmail drafts folder
Below is my code, which executes and completes with a 0 code but nothing is saved to my drafts folder. Can anyone please help ?
import imaplib
import ssl
import email.message
import email.charset
import time
class DraftMailDemo:
def send(self):
tls_context = ssl.create_default_context()
server = imaplib.IMAP4_SSL('imap.gmail.com')
#server.starttls(ssl_context=tls_context)
server.login('some.email#gmail.com', 'pass123')
# Select mailbox
server.select("INBOX.Drafts")
# Create message
new_message = email.message.Message()
new_message["From"] = "sender#mydomain.com"
new_message["To"] = "Jimmy <recipient#mydomain.com>"
new_message["Subject"] = "Your subject"
new_message.set_payload("""
This is your message.
It can have multiple lines and
contain special characters: äöü.
""")
# Fix special characters by setting the same encoding we'll use later to encode the message
new_message.set_charset(email.charset.Charset("utf-8"))
encoded_message = str(new_message).encode("utf-8")
print(encoded_message)
server.append('INBOX.Drafts', '', imaplib.Time2Internaldate(time.time()), encoded_message)
# Cleanup
#server.close()
server.logout()
if __name__ == '__main__':
mail = DraftMailDemo()
mail.send()
Output of the program:
/Library/Frameworks/Python.framework/Versions/3.10/bin/python3 /Users/prashanth/PycharmProjects/pythonTools/DraftMailDemo.py
b'From: sender#mydomain.com\nTo: Jimmy <recipient#mydomain.com>\nSubject: Your subject\nMIME-Version: 1.0\nContent-Type: text/plain; charset="utf-8"\nContent-Transfer-Encoding: base64\n\nCiAgICAgICAgVGhpcyBpcyB5b3VyIG1lc3NhZ2UuCiAgICAgICAgSXQgY2FuIGhhdmUgbXVsdGlw\nbGUgbGluZXMgYW5kCiAgICAgICAgY29udGFpbiBzcGVjaWFsIGNoYXJhY3RlcnM6IMOkw7bDvC4K\nICAgICAgICA=\n'
Process finished with exit code 0
I even tried this following code and it executes with a 0 exit code but still doesnt save anything to the Drafts folder.
import imaplib
import time
import email
def createdraft():
conn = imaplib.IMAP4_SSL('imap.gmail.com', port=993)
conn.login('some.email#gmail.com', 'pass123')
conn.select('[Gmail]/Drafts')
conn.append("[Gmail]/Drafts", '', imaplib.Time2Internaldate(time.time()), str(email.message_from_string('TEST')).encode('UTF-8'))
class SecondTryDraft:
pass
if __name__ == '__main__':
mail = SecondTryDraft()
createdraft()
My Environment:
Python : 3.10
OS : Mac OS Big Sur 11.6.5
All mail servers known to me added letters to INBOX.
It probably depends on the server settings.
You can try moving them after adding.
Ok, I finally figured this out after multiple tries and tweaking the other examples. I was able to create a MultiMime message that I can save to the Drafts folder and it works, hurray !!
It doesnt seem very efficient though (execution takes around 3-5 secs - I could use some suggestions on making it more efficient.
import imaplib
import time
from email.message import EmailMessage
from email.headerregistry import Address
def createdraft(lead_name, lead_email):
msg = EmailMessage()
msg['Subject'] = "My Introduction"
msg['From'] = Address("Jane Doe", "Jane.Doe", "gmail.com")
msg['To'] = Address(lead_name, lead_email.split("#")[0], lead_email.split("#")[1])
msg.set_type('text/html')
html_msg = f"""
<div class="gmail_default" style="color:rgb(0,0,255)"><font size="2">Hello {lead_name.split(" ")[0]},</font></div>
<div class="gmail_default" style="color:rgb(0,0,255)"><font size="2"><br></font></div>
<div class="gmail_default" style="color:rgb(0,0,255)"><font size="2">My name is John and I would like to connect with you.
<div class="gmail_default" style="color:rgb(0,0,255)"><font size="2">Look forward to hearing from you.<br></font></div>
<div class="gmail_default" style="color:rgb(0,0,255)"><font size="2"><br clear="all"></font></div>
<div><font size="2"><b><span style="color:rgb(0,0,255)">Jane</span></b></font></div>
<div><font size="2"><b><span style="color:rgb(0,0,255)">Mobile : 111-222-3333</span></b></font></div>
<div><font size="2"><b><span style="color:rgb(0,0,255)">Email : Jane.Doe#gmail.<wbr>com</span></b></font></div>
"""
msg.add_alternative(html_msg, subtype="html")
conn = imaplib.IMAP4_SSL('imap.gmail.com', port=993)
conn.login('jane.doe#gmail.com', 'pass123')
conn.select('[Gmail]/Drafts')
conn.append("[Gmail]/Drafts", '', imaplib.Time2Internaldate(time.time()), str(msg).encode('UTF-8'))
class CreateDraftMultiMimeText:
pass
if __name__ == '__main__':
mail = CreateDraftMultiMimeText()
createdraft('John Doe', 'John.Doe#gmail.com')
Environment :
Python : 3.10
OS : Mac OS Big Sur 11.6.5

Sending Mail in Python - Error code - SMTPDataError: 451, b 4.3.0 Mail server temporarily rejected message

I am able to send mail without issue when I implement the same code very plain without using any functions. But when I try to send mail using a function I am getting mail as my senders account is disabled and it is blocking my mail and account.
Have to implement a code for sending mails after certain filters are met in a function so that it can be used to send mail whenever wanted.
My code snippet:
import smtplib
def setup_mail():
global smtpObj,sender,receivers,message
sender = 'sample#gmail.com'
receivers = ['sample1#gmail.com','sample2#gmail.com']
message = """From: From Person <from#fromdomain.com>
To: To Person <to#todomain.com>
Subject: 1 MIN candle 15 points alert
TIME: watch out next 2 minutes
"""
smtpObj = smtplib.SMTP_SSL('smtp.gmail.com', 465)
smtpObj.login("sample#gmail.com","samplepassword")
setup_mail()
def sending_mails(smtpObj):
smtpObj.sendmail(sender, receivers, message)
for i in range(3):
sending_mails(smtpObj);
print("Successfully sent email")
The error i got,
Traceback (most recent call last): File "C:/Users/Arun/PycharmProjects/Astro/venv/Scripts/ZERODHA_DEV/sendmail.py", line 22, in sending_mails(smtpObj); File "C:/Users/Arun/PycharmProjects/Astro/venv/Scripts/ZERODHA_DEV/sendmail.py", line 20, in sending_mails smtpObj.sendmail(sender, receivers, message) File "C:\Python\lib\smtplib.py", line 888, in sendmail raise SMTPDataError(code, resp) smtplib.SMTPDataError: (451, b'4.3.0 Mail server temporarily rejected message. s77sm14888153pfc.164 - gsmtp')
However it works with a simple code like,
import smtplib
global smtpObj,sender,receivers,message
sender = 'sample#gmail.com'
receivers = ['sample1#gmail.com','sample2#gmail.com']
message = """From: From Person <from#fromdomain.com>
To: To Person <to#todomain.com>
Subject: 1 MIN candle 15 points alert
TIME: watch out next 2 minutes
"""
smtpObj = smtplib.SMTP_SSL('smtp.gmail.com', 465)
smtpObj.login("sample#gmail.com","samplepassword")
for i in range(3):
smtpObj.sendmail(sender, receivers, message)
print("Successfully sent email")
The immediate problem is that your message is indented; a valid SMTP message contains two literal adjacent newlines to demarcate the headers from the body.
While you can assemble simple email messages from ASCII strings, this is not tenable for real-world modern email messages. You really want to use the email library (or a higher level third-party wrapper or replacement) to handle all the corner cases of email message encapsulation, especially if you are not an expert on email and MIME yourself.

Sending Email with Python using Outlook desktop application - clipboard as the input for email address

I am trying to send the following email automated with Python but i keep get an error. I would like to run the script and then for it to ask me for input on which email address to send it to. But I keep getting an error. If I put an actual email address in the Msg.To section it works but I was hoping that every time I run this script it would ask me which email address to send to (originally I was trying to have it simply use whats on my clipboard as the input but that seemed too complicated so I relegated to input prompt instead).
Here is my code:
emailrecepient = input("enter email address")
import win32com.client
o = win32com.client.Dispatch("Outlook.Application")
Msg = o.CreateItem(0)
Msg.Importance = 2
Msg.Subject = 'SUBJECT'
Msg.HTMLBody = """<p>Hello,<br>"""
Msg.To = "sender"
Msg.Send()

Is there any way by which I can name the attached pdf file in flask mail?

I am using flask-mail to send a mail that would include a pdf document as an attachment,
The problem is when I receive it in my email the document's name turns out to be "noname" (without any extension), Even though this document is downloadable and readable there are some exceptional cases (probably 1 out of 10) where the document cannot be opened(probably because the extension is not set).
def send_mail_flask_to_user(self, doc_name, document_id, email,approve):
app.config.update(self.mail_settings)
mail = Mail(app)
with app.app_context():
msg = Message(sender=app.config.get(
"MAIL_USERNAME"), recipients=[email])
msg.subject = '{} Coriolis Tech'.format(doc_name)
msg.body=""" Dear {},
your request for {} has be approved and generated,please find the attachment for the same""".format(email.split('.')[0],doc_name)
working_dir=os.getcwd()
link = "https://docs.google.com/document/d/{}/".format(document_id)
if (approve==True):
with open(working_dir+"/generated_docs/"+document_id+".pdf",'rb') as fh:
msg.attach(working_dir+"/"+document_id+".pdf","application/pdf",fh.read())
elif(approve==False):
msg.body=""" Your {} is rejected ,contact Division of Human Resource Coriolis Technologies to know more""".format(doc_name)
mail.send(msg)
This problem only persists on Ubuntu 14.04 ,where as it works fine on a Windows machine
The filename parameter has to be a string.extension(eg: "something.pdf") to name the attachment that would be received
eg: your 'abcdcdhhcbdhbcvh.pdf' file that you want to attach would be named as "something.pdf" in the attachment
Hence replace the msg.attach(working_dir+"/"+document_id+".pdf","application/pdf",fh.read()) line with msg.attach(filename="something.pdf",disposition="attachment",content_type="application/pdf",data=fh.read())

Python's Email Message library output not getting accepted by Outlook 365 when i have a named attachments from

I've created a sample function to test sending emails with an attached html file, which i intend to use for reporting on automated test runs in the future (replacing an existing external powershell script). Note that I'm attaching the html file, not using the html as inline text in the body. I'm using our company's mailgun smtp account service to send the email.
I seem to have an issue with Outlook 365 (web hosted - uses the outlook.office.com domain) either rejecting or blocking the sent email, but interestingly the same email is received and accepted by my personal hotmail address (outlook.live.com domain). I've found Outlook 365 blocks or does not accept the email when I attempt to name the file in the email message object. But if I don't name it, it will come through (with a default name of "ATT00001.htm" ).
My code for this is below but they key line seems to be
msg.add_attachment(open_file.read(), maintype='text', subtype='html', filename=filename)
If I drop the filename key it works (but with a default assigned filename) e.g.
msg.add_attachment(open_file.read(), maintype='text', subtype='html')
I have a suspicion there is something in the attachment's header or Content-disposition that Outlook 365 doesn't agree with, but i'm not sure what it is or how to work around.
I'm using the following (Python 3.6.5, on Windows 10 machine, smtplib and email.message seem to be built in)
Here is the code:
import smtplib
from email.message import EmailMessage
import os
def send_mail():
MAILGUN_SMTP_LOGIN = "<my company's mailgun login>"
MAILGUN_SMTP_PASSWORD = "<my company's mailgun password>"
fromaddr = "muppet#sharklasers.com" # the from address seems to be inconsequential
toaddr = ['me#mycompanysdomainusingoffice365.com.au', 'me#hotmail.com']
msg = EmailMessage()
msg.preamble = 'This is preamble. Not sure where it should show in the email'
msg['From'] = fromaddr
msg['To'] = ', '.join(toaddr)
msg['Subject'] = 'Testing attached html results send'
msg.set_content(""" This is a test of attached html """)
filename = 'api_automatedtests_20180903_1341.html'
filepath = os.path.abspath('D:/work/temp/api_automatedtests_20180903_1341.html')
open_file = open(filepath, "rb")
# msg.make_mixed()
msg.add_attachment(open_file.read(), maintype='text', subtype='html', filename=filename)
# msg.add_attachment(open_file.read(), maintype='text', subtype='html')
server = smtplib.SMTP(host="smtp.mailgun.org", port=587)
server.ehlo()
server.starttls()
server.login(MAILGUN_SMTP_LOGIN, MAILGUN_SMTP_PASSWORD)
server.set_debuglevel(1)
server.send_message(msg)
server.quit()
if __name__ == "__main__":
send_mail()
What I've tried
Tried sending with the same code using a textfile (with appropriate types). e.g.
msg.add_attachment(open_file.read(), maintype='text', subtype='plain', filename=filename)
Result: This works as expected (comes through with the given name - the filename is a string variable e.g. testfile.txt)
adding msg.make_mixed() to make sure it is identified as a multipart message. Result: No effect
Turning on the smtp debug level 1, Result: Mailgun says that everything has worked fine (and the messages do appear as expected in my hotmail account)
Not using the filename key in the msg.add_attachment call.
Result: This works the attachment comes through at ATT00001.htm
Interestingly the default name is *.htm while the filename I'm trying to use is *.html
Tried using a filename with *.htm and a subtype of 'htm' (instead of html)
Result: Same as for html (received on hotmail but not on outlook 365)
Tried using the generic types of maintype=''application', subtype='octet-stream'.
e.g. msg.add_attachment(open_file.read(), maintype='application', subtype='octet-stream', filename=filename)
Result: Same as for html (received on hotmail but not on outlook 365)
Tried using mimetypes.guess as shown in this link
https://docs.python.org/3.6/library/email.examples.html
ctype, encoding = mimetypes.guess_type(path)
if ctype is None or encoding is not None:
# No guess could be made, or the file is encoded (compressed), so
# use a generic bag-of-bits type.
ctype = 'application/octet-stream'
maintype, subtype = ctype.split('/', 1)
with open(path, 'rb') as fp:
msg.add_attachment(fp.read(),
maintype=maintype,
subtype=subtype,
filename=filename)
Result: It's determined as maintype='text', subtype='html' and I get the same result as with my original code (ie arrives in hotmail but blocked by 365).
Checking my spam and clutter folders - was not there
Any suggestions on why the use of filename would be breaking it?
Update
After sending to a other email addresses with various providers I discovered:
1) muppet#sharklasers.com was not a trusted sender (can change this)
2) I discovered the attachment was being flagged as unsafe. The html file comes from pytest's html report with the single file option. It contains javascript for row expanders. Gmail warns the attachment may not be safe (office 365 just straight out blocks the email altogether).
Not sure how to work around 2). I can email the same file to myself between outlook 365 and gmail and vice versa and the file doesn't get blocked. It only get's blocked when I use the above script using python's libraries and Mailgun SMTP. I suspect there is something I need to change in the email header to get around this. But I don't know what.
There seems to be some connection between trying to add the filename and the attachment being marked as unsafe
Okay I figured it out. The problem was the content-type needed to include "name=filename" in it's value.
Also I needed to use maintype='multipart', subtype='mixed'.
I have 2 solutions.
solution 1
import smtplib
from email.message import EmailMessage
import os
def send_mail(body_text, fromaddr, recipient_list, smtp_login, smtp_pass, file_path):
msg = EmailMessage()
msg.preamble = 'This is preamble. Not sure where it should show'
msg['From'] = fromaddr
msg['To'] = ', '.join(recipient_list)
msg['Subject'] = 'API Testing results'
msg.set_content(body_text)
filename = os.path.basename(file_path)
open_file = open(file_path, "rb")
msg.add_attachment(open_file.read(), maintype='multipart', subtype='mixed; name=%s' % filename, filename=filename)
server = smtplib.SMTP(host="smtp.mailgun.org", port=587)
server.ehlo()
server.starttls()
server.login(smtp_login, smtp_pass)
server.send_message(msg)
server.quit()
if __name__ == "__main__":
smtp_login = "<my smtp login>"
smtp_pass = "<my smtp password>"
recipient_list = ['user1#mycompany.com.au', 'user2#mycompany.com.au']
file_path = os.path.abspath('D:/work/temp/api_automatedtests_20180903_1341.html')
body_text = "test results for 03/09/2018 "
fromaddr = 'autotesting#mycompany.com.au'
send_mail(body_text=body_text, recipient_list=recipient_list, smtp_login=smtp_login, smtp_pass=smtp_pass,
file_path=file_path)
solution 2 (according to the documentation using the email.mime libraries is a legacy solution and the EmailMessage method is supposed to be used in preference.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
import os
def send_mail(body_text, fromaddr, recipient_list, smtp_login, smtp_pass, file_path):
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = ', '.join(recipient_list)
msg['Subject'] = "Sending API test results"
msg.attach(MIMEText(body_text, 'plain'))
filename = os.path.basename(file_path)
attachment = open(file_path, "rb")
part = MIMEBase('multipart', 'mixed; name=%s' % filename)
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)
msg.attach(part)
server = smtplib.SMTP(host="smtp.mailgun.org", port=587)
server.starttls()
server.login(smtp_login, smtp_pass)
text = msg.as_string()
server.set_debuglevel(1)
server.sendmail(fromaddr, recipient_list, text)
server.quit()
if __name__ == '__main__':
smtp_login = "<my smtp login>"
smtp_pass = "<my smtp password>"
recipient_list = ['user1#mycompany.com.au', 'user2#mycompany.com.au']
file_path = os.path.abspath('D:/work/temp/api_automatedtests_20180903_1341.html')
body_text = " Api test results for 03/09/2018 "
fromaddr = "autotest#mycompany.com.au"
send_mail(body_text=body_text, fromaddr=fromaddr, recipient_list=recipient_list, smtp_login=smtp_login, smtp_pass=smtp_pass,
file_path=file_path)

Resources