How to match today's date in dataframe and send email messages - python

I learning how to use pandas to deal with data and I find it pretty cool and fun. I am trying to build an automatic email system.
But now I am stocked with the following:
This question makes reference to one of my old questions here.
This is how may data-set looks like:
I want to check if datatime_from is today and if it is true, take the email-address of that row and send an email message. I am using pandas as for the dataframe and my idea was to use smtplib for sending email messages, but I am open to use other libraries.
Here is my code until now:
import smtplib
import pandas
def send_me_email():
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login('xxx#gmail.com', 'xxxxxxx')
msg = "YOUR MESSAGE!"
server.sendmail("YOUR EMAIL ADDRESS", "THE EMAIL ADDRESS TO SEND TO", msg)
server.quit()
msg = "YOUR MESSAGE!"
server.sendmail("xxx#gmail.com", "xxx#gmail.com", msg)
server.quit()
csv = pandas.read_csv('testfile.csv', delimiter=',')
#csv['datetime_from'].dtype
csv['datetime_from'] = pandas.to_datetime(csv['datetime_from'], errors='coerce')
#csv['datetime_from'].dtype
today_date = pandas.datetime.today().date()
csv2 = csv['datetime_from'].dt.date == today_date
csv['datetime_from'].where(csv).apply(send_me_email())
This is not working correctly, I cannot figure it out how to grab for all actual dates the corresponding email-addresses and send an email to those. The data file will be growing with new coming input every day.
Any ideas will be appreciated.

You'll need to use the mask you get to index your data frame:
csv2 = csv[csv['datetime_from'].dt.date == today_date]
Furthermore, your send_me_email must take a parameter which df.apply passes to it:
def send_me_email(email):
...
This parameter is the E-Mail. Make sure you modify the body of your function to handle it accordingly.
You may now apply your function using df.apply. Do not call your function. You must pass it (without the ()):
csv2['E-Mail'].apply(send_me_email)

Related

Python program for email automation doesnt read the whole excel data

I wrote an email-sending program in Python. The idea is to just add Excel data to the emails, press one button, and send the email to everyone.
Now, I got everything done, but one thing is failing: it actually reads only one email at a time. If I write the emails horizontally in different splits, it combines them into one email but only sends it to the first one. If I write it vertically, it only reads one email at a time; that means I have to change the program every time, moving or deleting the highest one (vertical) so it will send the email to the next one in the row. My goal is for it to read every email and send it to every individual.
This is my code:
import smtplib, ssl
import pandas as pd
from email.message import EmailMessage
sender = "..."
password = "..."
subject = "..."
bodymessage = "..."
context = ssl.create_default_context()
server = smtplib.SMTP_SSL("smtp.gmail.com", 465, context = context)
server.login(sender, password)
with open("C:\\Users\\Lol\\Desk\\Python bulk emails\\Maily.csv", "r", encoding="UTF8") as csvfile:
datareader = df = pd.read_csv(csvfile)
for row in datareader:
em = EmailMessage()
em["From"] = sender
em["to"] = row
em["subject"] = subject
em.set_content(bodymessage)
server.send_message(em)
print("The message sent")
server.close()
print("Done")
I've tried using different encodings (Latin-1, UTF-16, and UTF-8); UTF-8 was the only one that worked; also, I tried different readers (csv_reader and pandas); now I am using pandas. It might help to let him read the data in chunks (pd.read_csv("sample.csv", chunksize=${2:10)), but I don't know how to install that, because every time I tried this, it said: "It has to be an integer".

Reply to an Outlook email using the MessageID and Win32com module in Python

So I know how to look through the inbox (or any other folder) and find emails to reply to. However in my case, I have a .msg email file from which I extract the MessageID, and I'm looking to use win32com module to reply to that specific email.
Basically I'm looking for something like this:
from extract_msg import Message
msg = Message("message.msg")
outlook = win32com.client.Dispatch('outlook.application')
mail = outlook.CreateItem(0x0)
mail.To = "; ".join(to)
mail.Subject = subject
mail.Body = body
mail.InReplyTo = msg.messageId
I understand that something similar is doable using the smtplib module using:
message['In-Reply-To'] = msg.messageId
but I cannot get smtplb to work with Outlook. And thus, I'm using win32com.
The PR_IN_REPLY_TO_ID property should be set to the PR_INTERNET_MESSAGE_ID property value. Make sure that such value exists in Outlook messages. You can get the value in Outlook in the following way (the sample is in C# but the Outlook object model is common for all kind of programming languages):
string PR_INTERNET_MESSAGE_ID = "http://schemas.microsoft.com/mapi/proptag/0x1035001F";
Microsoft.Office.Interop.Outlook.PropertyAccessor pal = mailItem.PropertyAccessor;
string Internet_Message_Id = pal.GetProperty(PR_INTERNET_MESSAGE_ID).ToString();
You need to set the PR_IN_REPLY_TO_ID MAPI property (DASL name "http://schemas.microsoft.com/mapi/proptag/0x1042001F") using MailItem.PropertyAccessor.SetProperty.

Python mail inserts space every 171 characters

I am trying to write a python script to send an email that uses html formatting and involves a lot of non-breaking spaces. However, when I run it, some of the &nbsp strings are interrupted by spaces that occur every 171 characters, as can be seen by this example:
#!/usr/bin/env python
import smtplib
import socket
from email.mime.text import MIMEText
emails = ["my#email.com"]
sender = "test#{0}".format(socket.gethostname())
message = "<html><head></head><body>"
for i in range(20):
message += " " * 50
message += "<br/>"
message += "</body>"
message = MIMEText(message, "html")
message["Subject"] = "Test"
message["From"] = sender
message["To"] = ", ".join(emails)
mailer = smtplib.SMTP("localhost")
mailer.sendmail(sender, emails, message.as_string())
mailer.quit()
The example should produce a blank email that consists of only spaces, but it ends up looking something like this:
&nbsp ;
&nb sp;
& nbsp;
&nbs p;
&n bsp;
Edit: In case it is important, I am running Ubuntu 15.04 with Postfix for the smtp client, and using python2.6.
I can replicate this in a way but my line breaks come every 999 characters. RFC 821 says maximum length of a line is 1000 characters including the line break so that's probably why.
This post gives a different way to send a html email in python, and i believe the mime type "multipart/alternative" is the correct way.
Sending HTML email using Python
I'm the developer of yagmail, a package that tries to make it easy to send emails.
You can use the following code:
import yagmail
yag = yagmail.SMTP('me#gmail.com', 'mypassword')
for i in range(20):
message += " " * 50
message += "<br/>"
yag.send(contents = message)
Note that by default it will send a HTML message, and that it also adds automatically the alternative part for non HTML browsers.
Also, note that omitting the subject will leave an empty subject, and without a to argument it will send it to self.
Furthermore, note that if you set yagmail up correctly, you can just login using yag.SMTP(), without having to have username & password in the script (while still being secure). Omitting the password will prompt a getpass.
Adding an attachment is as simple as pointing to a local file, e.g.:
yag.send(contents = [message, 'previously a lot of whitespace', '/local/path/file.zip']
Awesome isn't it? Thanks for the allowing me to show a nice use case for yagmail :)
If you have any feature requests, issues or ideas please let me know at github.

Python, IMAP and GMail. Mark messages as SEEN

I have a python script that has to fetch unseen messages, process it, and mark as seen (or read)
I do this after login in:
typ, data = self.server.imap_server.search(None, '(UNSEEN)')
for num in data[0].split():
print "Mensage " + str(num) + " mark"
self.server.imap_server.store(num, '+FLAGS', '(SEEN)')
The first problem is that, the search returns ALL messages, and not only the UNSEEN.
The second problem is that messages are not marked as SEEN.
Can anybody give me a hand with this?
Thanks!
import imaplib
obj = imaplib.IMAP4_SSL('imap.gmail.com', '993')
obj.login('user', 'password')
obj.select('Inbox') <--- it will select inbox
typ ,data = obj.search(None,'UnSeen')
obj.store(data[0].replace(' ',','),'+FLAGS','\Seen')
I think the flag names need to start with a backslash, eg: \SEEN
I am not so familiar with the imaplib but I implement this well with the imapclient module
import imapclient,pyzmail,html2text
from backports import ssl
context=ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
iobj=imapclient.IMAPClient('outlook.office365.com', ssl=True, ssl_context=context)
iobj.login(uname,pwd)# provide your username and password
iobj.select_folder('INBOX',readonly=True)# Selecting Inbox.
unread=iobj.search('UNSEEN')# Selecting Unread messages, you can add more search criteria here to suit your purpose.'FROM', 'SINCE' etc.
print('There are: ',len(unread),' UNREAD emails')
for i in unread:
mail=iobj.fetch(i,['BODY[]'])#I'm fetching the body of the email here.
mcontent=pyzmail.PyzMessage.factory(mail[i][b'BODY[]'])#This returns the email content in HTML format
subject=mcontent.get_subject()# You might not need this
receiver_name,receiver_email=mcontent.get_address('from')
mail_body=html2text.html2text(mcontent.html_part.get_payload().decode(mcontent.html_part.charset))# This returns the email content as text that you can easily relate with.
Let's say I want to just go through the unread emails, reply the sender and mark the email as read. I'd call the smtp function from here to compose and send a reply.
import smtplib
smtpobj=smtplib.SMTP('smtp.office365.com',587)
smtpobj.starttls()
smtpobj.login(uname,pwd)# Your username and password goes here.
sub='Subject: '+str(subject)+'\n\n'# Subject of your reply
msg='Thanks for your email! You're qualified for the next round' #Some random reply :(
fullmsg=sub+new_result
smtpobj.sendmail(uname,test,fullmsg)# This sends the email.
iobj.set_flags(i,['\\Seen','\\Answered'])# This marks the email as read and adds the answered flag
iobj.append('Sent Items', fullmsg)# This puts a copy of your reply in your Sent Items.
iobj.logout()
smtpobj.logout()
I hope this helps

python-xmpp and looping through list of recipients to receive and IM message

I can't figure out the problem and want some input as to whether my Python code is incorrect, or if this is an issue or design limitation of Python XMPP library. I'm new to Python by the way.
Here's snippets of code in question below. What I'd like to do is read in a text file of IM recipients, one recipient per line, in XMPP/Jabber ID format. This is read into a Python list variable.
I then instantiate an XMPP client session and loop through the list of recipients and send a message to each recipient. Then sleep some time and repeat test. This is for load testing the IM client of recipients as well as IM server. There is code to alternately handle case of taking only one recipient from command line input instead of from file.
What ends up happening is that Python does iterate/loop through the list but only last recipient in list receives message. Switch order of recipients to verify. Kind of looks like Python XMPP library is not sending it out right, or I'm missing a step with the library calls, because the debug print statements during runtime indicate the looping works correctly.
recipient = ""
delay = 60
useFile = False
recList = []
...
elif (sys.argv[i] == '-t'):
recipient = sys.argv[i+1]
useFile = False
elif (sys.argv[i] == '-tf'):
fil = open(sys.argv[i+1], 'r')
recList = fil.readlines()
fil.close()
useFile = True
...
# disable debug msgs
cnx = xmpp.Client(svr,debug=[])
cnx.connect(server=(svr,5223))
cnx.auth(user,pwd,'imbot')
cnx.sendInitPresence()
while (True):
if useFile:
for listUser in recList:
cnx.send(xmpp.Message(listUser,msg+str(msgCounter)))
print "sending to "+listUser+" msg = "+msg+str(msgCounter)
else:
cnx.send(xmpp.Message(recipient,msg+str(msgCounter)))
msgCounter += 1
time.sleep(delay)
Never mind, found the problem. One has to watch out for the newline characters at the end of a line for the elements in a list returned by file.readlines(), so I had to strip it out with .rstrip('\n') on the element when sending out message.

Categories

Resources