This code runs and does download the attachments as expected.
That said, It writes all attachments to the directory on my PC. I only want to include an attachment with a .html file type. Anything else should be omitted.
Secondly, I would like it to only import the .html attachment if the subject line = "Whatever" if this is true then I would like it to save to a specific subfolder in the PC directory. So for example: if subject = "Whatever1" then save to c:\Desktop\Folder\Subfolder1, if subject = "Whatever2" then save to c:\Desktop\Folder\Subfolder2 etc
import email, imaplib, os
#Credentials
username = 'myusername'
password = 'mypassword'
#SaveTo Directory on PC
attachment_dir = "C:/Desktop\Folder\Subfolder"
#Functions
def get_body(msg):
if msg.is_multipart():
return get_body(msg.get_payload(0))
else:
return msg.get_payload(None,True)
def get_attachments(msg):
for part in msg.walk():
if part.get_content_maintype()=='multipart':
continue
if part.get('Content-disposition') is None:
continue
filename = part.get_filename()
if bool(filename) :
filepath =os.path.join(attachment_dir, filename)
with open(filepath,'wb')as f:
f.write(part.get_payload(decode=True))
def search(key,value,mail):
result, data = mail.search(none,key,'"()"'.format(value))
return data
def get_emails(result_bytes):
msgs = []
for num in result_bytes[0].split():
typ,data = mail.fetch(num,'(RCF822)')
msgs.append(data)
return msgs
#Create Connection
mail = imaplib.IMAP4_SSL("imap.gmail.com")
mail.login(username, password)
#Which Gmail Folder to Select?
mail.select("Inbox")
result, data = mail.fetch(b'12','(RFC822)')
raw = email.message_from_bytes(data[0][1])
get_attachments(raw)
from imap_tools import MailBox
# get all attachments from INBOX and save them to files
with MailBox('imap.my.ru').login('acc', 'pwd', 'INBOX') as mailbox:
for msg in mailbox.fetch():
print(msg.subject)
for att in msg.attachments:
print('-', att.filename, att.content_type)
with open('C:/1/{}'.format(att.filename), 'wb') as f:
f.write(att.payload)
lib: https://github.com/ikvk/imap_tools
for mList in range(numMessages):
for msg in msg.startswith("Subject:")
if msg.startswith('Subject'):
print(msg)
break
This should parse the subject line, so you can distinguish by whatever you want the subject to be.
Related
import imaplib
import email
from email.header import decode_header
import webbrowser
import os
# account credentials
username = "example#stack.com"
password = "exapleforstack"
imap_server = "imap.one.com"
def clean(text):
# clean text for creating a folder
return "".join(c if c.isalnum() else "_" for c in text)
# create an IMAP4 class with SSL
imap = imaplib.IMAP4_SSL(imap_server)
# authenticate
imap.login(username, password)
status, messages = imap.select("INBOX")
imap.search(None, 'SUBJECT', '"exampleforstack"')
# number of top emails to fetch
N = 3
# total number of emails
messages = int(messages[0])
for i in range(messages, messages-N, -1):
# fetch the email message by ID
res, msg = imap.fetch(str(i), "(RFC822)")
for response in msg:
if isinstance(response, tuple):
# parse a bytes email into a message object
msg = email.message_from_bytes(response[1])
# decode the email subject
subject, encoding = decode_header(msg["Subject"])[0]
if isinstance(subject, bytes):
# if it's a bytes, decode to str
subject = subject.decode(encoding)
# decode email sender
From, encoding = decode_header(msg.get("From"))[0]
if isinstance(From, bytes):
From = From.decode(encoding)
print("Subject:", subject)
print("From:", From)
# if the email message is multipart
if msg.is_multipart():
# iterate over email parts
for part in msg.walk():
# extract content type of email
content_type = part.get_content_type()
content_disposition = str(part.get("Content-Disposition"))
try:
# get the email body
body = part.get_payload(decode=True).decode()
except:
pass
if content_type == "text/plain" and "attachment" not in content_disposition:
# print text/plain emails and skip attachments
print(body)
elif "attachment" in content_disposition:
# download attachment
filename = part.get_filename()
if filename:
folder_name = clean(subject)
if not os.path.isdir(folder_name):
# make a folder for this email (named after the subject)
os.mkdir(folder_name)
filepath = os.path.join(folder_name, filename)
# download attachment and save it
open(filepath, "wb").write(part.get_payload(decode=True))
else:
# extract content type of email
content_type = msg.get_content_type()
# get the email body
body = msg.get_payload(decode=True).decode()
if content_type == "text/plain":
# print only text email parts
print(body)
if content_type == "text/html":
# if it's HTML, create a new HTML file and open it in browser
folder_name = clean(subject)
if not os.path.isdir(folder_name):
# make a folder for this email (named after the subject)
os.mkdir(folder_name)
filename = "index.html"
filepath = os.path.join(folder_name, filename)
# write the file
open(filepath, "w").write(body)
# open in the default browser
webbrowser.open(filepath)
print("="*100)
# close the connection and logout
imap.close()
imap.logout()
I tried using the search method a couple different ways, like:
res, msg = imap.search(None, 'SUBJECT', "example")
and
res, msg = imap.search(None, 'SUBJECT, "example"')
but my code just gives an error and automatically fetches the most recent 3.
I've tried replacing the line:
res, msg = imap.fetch(str(i), "(RFC822)")
with
res, msg = imap.search(None, 'SUBJECT', '"example"')
but the program returns nothing at all.
how would I go about implementing the search I got this code from pythoncode and altered its credentials.
But I'm not sure why I can't implement the search function.
I have the code written below:
class SendEmail:
def __init__(self, eSubject, eBody, eAttachmnts=None):
self.eSubject = eSubject
self.eAttachments = eAttachmnts
self.eBody = HTMLBody(eBody)
def setSend(self):
print("Enter your Email Credentials")
credsJson, usr, pWd = getCredential()
self.setEmailParams(usr, pWd)
def setEmailParams(self, usrNm, Pwd):
creds = Credentials(usrNm, Pwd)
config = Configuration(server=c.emailServer, credentials=creds)
account = Account(
primary_smtp_address=c.sourceSmtpAddress,
autodiscover=False,
config=config,
access_type=DELEGATE,
)
self.sendEmail(account)
def sendEmail(self, account):
msg = Message(
account=account,
folder=account.sent,
subject=self.eSubject,
body=self.eBody,
to_recipients=c.receipients,
)
for aName, aContent in self.eAttachments or []:
msg.attach(FileAttachment(name=aName, content=aContent))
msg.send_and_save()
I'm calling this from my main script as :
attachments = []
for i in attachmntLst:
with open(i, 'rb') as f:
content = f.read()
attachments.append((i, content))
emailObject = SendEmail(subjectLine, DF.to_html(), attachments)
emailObject.setSend()
subjectLine is a string. DF is a pandas dataframe. I want the dataframe to be printed in a tabular form as email body, hence used to_html(). attachmentLst is a list of filenames that I want attached to the email.
The code works well in sending the email with appropriate email body in tabular format. However no attachments are added to it, and I don't see any error messages as well. What is going wrong?
I have emails that will be flagged by gmail settings to move to a certain label called "Test". This script I am writing when ran, downloads any attachments in that label then moves all those emails to another label called "Checked" (to keep that label clear).
I have the download and parsing part done but I can't seem to manage moving the emails.
Here is the completed part of the program:
import imaplib
import email
import os
import base64
#import Const
user = 'email#gmail.com'
password = 'imnottellingyou'
imap_url = 'imap.gmail.com'
def auth(user, password, imap_url):
con = imaplib.IMAP4_SSL(imap_url)
con.login(user, password)
return con
con = auth(user, password, imap_url)
con.select('Test')
type, data = con.search(None, 'ALL')
mail_ids = data[0]
id_list = mail_ids.split()
print(id_list)
print(mail_ids)
for num in data[0].split():
typ, data = con.fetch(num, '(RFC822)')
raw_email = data[0][1]
# converts byte literal to string removing b''
raw_email_string = raw_email.decode('utf-8')
email_message = email.message_from_string(raw_email_string)
for part in email_message.walk():
if part.get_content_maintype() == 'multipart':
continue
if part.get('Content-Disposition') is None:
continue
fileName = part.get_filename()
if bool(fileName):
filePath = os.path.join(
'C:/Users/User/Desktop/test', fileName)
if not os.path.isfile(filePath):
fp = open(filePath, 'wb')
fp.write(part.get_payload(decode=True))
fp.close()
for uid in id_list:
con.uid('STORE', uid, '+X-GM-LABELS', 'Checked')
con.uid('STORE', uid, '-X-GM-LABELS', 'Test')
Here is the trouble area. This is what I have tried:
#after emails in label have been checked for attachments and downloaded
#emails will be transferred to a "checked" labe
for uid in id_list:
con.uid('STORE', uid, '+X-GM-LABELS', 'Checked')
con.uid('STORE', uid, '-X-GM-LABELS', 'Test')
The program executes fine, and no error messages appear but nothing changes in my gmail inbox.
Finally was able to come up with a solution.
for uid in id_list:
#adds the checked label (new label) to all emails that are in the id list
con.store(uid, '+X-GM-LABELS', '(Checked)')
#instead of "removing" original label it deletes the email from the label
#since labels act like folders in gmail
con.store(uid,'+FLAGS', '\\Deleted')
I m new to python and i was trying to send attached email through Gmail and the path of attachment i'm giving unable to locate Python.
class Email(object):
def __init__(self, from_, to, subject, message, message_type='plain',
attachments=None, cc=None, message_encoding='us-ascii'):
self.email = MIMEMultipart()
self.email['From'] = from_
self.email['To'] = to
self.email['Subject'] = subject
if cc is not None:
self.email['Cc'] = cc
text = MIMEText(message, message_type, message_encoding)
self.email.attach(text)
if attachments is not None:
mimetype, encoding = guess_type(attachments)
if mimetype ==None:
mimetype = "text/html"
mimetype = mimetype.split('/', 1)
with open(os.path.join(attachments, 'TestReport.html')) as f:
attachment = MIMEBase(mimetype[0], mimetype[1])
attachment.set_payload(f.read())
f.close()
encode_base64(attachment)
attachment.add_header('Content-Disposition', 'attachment',
filename=os.path.basename(attachment))
self.email.attach(attachment)
Below code is the file I'm executing and throwing an error with open(os.path.join(attachments, 'TestReport.html')) as f:
IOError: [Errno 2] No such file or directory: 'C:/RelianceJio/wallet-fp-automation/email_utils\TestReport.html'
from email_utils.Email import EmailConnection, Email
config = ConfigParser.ConfigParser()
config.read(getcwd() + "/configuration.ini")
print 'I need some information...'
name = 'Lokesh Reddy'
email = 'lokeshreddyqa#gmail.com'
password = '***'
mail_server = 'smtp.gmail.com'
to_email = 'lokeshreddz#gmail.com'
to_name = 'Lokesh Reddy'
subject = 'Sending mail easily with Python'
message = 'here is the message body'
#os.chdir(getcwd() + "\ TestReport.html")
MYDIR = os.path.dirname(__file__)
attachments =MYDIR
print 'Connecting to server...'
server = EmailConnection(mail_server, email, password)
print 'Preparing the email...'
email = Email(from_='"%s" <%s>' % (name, email), # you can pass only email
to='"%s" <%s>' % (to_name, to_email), # you can pass only email
subject=subject, message=message, attachments=attachments)
print 'Sending...'
server.send(email)
print 'Disconnecting...'
server.close()
print 'Done!'
You are trying to attach TestReport.html present in the floder 'C:/RelianceJio/wallet-fp-automation/email_utils\'. Please check whether the file is present in the folder specified. If not make sure that the file is present in that folder or else pass the correct attachment folder.
Try:
C:\\RelianceJio\\wallet-fp-automation\\email_utils\\TestReport.html
You gave "\" instead of "\".
Your directory:
C:/RelianceJio/wallet-fp-automation/email_utils**\**TestReport.html
I'm downloading messages from IMAP with imaplib into a mbox (with mailbox module):
import imaplib, mailbox
svr = imaplib.IMAP4_SSL('imap.gmail.com')
svr.login('myname#gmail.com', 'mypaswword')
resp, [countstr] = svr.select("[Gmail]/All Mail", True)
mbox = mailbox.mbox('mails.mbox')
for n in range(...):
resp, lst1 = svr.fetch(n, 'UID') # the UID of the message
resp, lst2 = svr.fetch(n, '(RFC822)') # the message itself
mbox.add(lst2[0][1]) # add the downloaded message to the mbox
#
# how to store the UID of this current mail inside mbox?
#
Let's download the mails with UID = 1 .. 1000. Next time, I would like to begin at the 1001th message and not from the 1st. However, mailbox.mbox does not store the UID anywhre. So next time I will open the mbox file, it will be impossible to know where we stopped.
Is there a natural way with the module mailbox to store the UID of the emails?
Or maybe I don't use mailbox + imaplib the way it should ?
I hope it will be useful:
1) libraries and environment Win7 Anaconda3-4.3.1-Windows-x86_64.exe (new is available but that what I have used
2) To list all your mailboxes:
import getpass, imaplib, sys
def main():
hostname = 'my.mail.server'
username = 'my_user_name'
m = imaplib.IMAP4_SSL(hostname)
m.login(username, 'passowrd')
try:
print('Capabilities:', m.capabilities)
print('Listing mailboxes ')
status, data = m.list()
print('Status:', repr(status))
print('Data:')
for datum in data:
print(repr(datum))
finally:
m.logout()
if __name__ == '__main__':
main()
3) Using generated above information we can dump all email messages from mail server to the directories:
import getpass, imaplib, sys, email, os , io
import codecs
BASE_NAME = 'msg_no_'
BASE_DIR = 'D:/my_email/'
def writeTofile(mailDir, partOfName, msg ):
## no need of dos backslash -- newDir = BASE_DIR + mailDir.replace('/', '\\')
newDir = BASE_DIR + mailDir
if not os.path.exists(newDir):
os.makedirs(newDir)
os.chdir(newDir)
# print('Dir:' + os.getcwd() )
file_name = BASE_NAME + partOfName + '.eml'
# print('Write:' + file_name)
fw = open(newDir + '/' + file_name,'w', encoding="utf-8")
fw.write( msg )
fw.close()
return
def processMailDir(m, mailDir):
print('MailDIR:' + mailDir)
m.select(mailbox=mailDir, readonly=True)
typ, data = m.search(None, 'ALL')
for num in data[0].split():
typ, data = m.fetch(num, '(RFC822)')
msg = email.message_from_bytes(data[0][1])
smsg = msg.as_bytes().decode(encoding='ISO-8859-1')
writeTofile(mailDir, num.decode(), smsg )
m.close()
return
def main():
if len(sys.argv) != 3:
hostname = 'my.mail.server'
username = 'my_username'
m = imaplib.IMAP4_SSL(hostname)
m.login(username, 'password')
else:
hostname, username = sys.argv[1:]
m = imaplib.IMAP4_SSL(hostname)
m.login(username, getpass.getpass())
try:
print('Start...')
processMailDir(m, 'INBOX')
processMailDir(m, 'Sent')
processMailDir(m, 'archive/2013/201301')
processMailDir(m, 'archive/2013/201302')
# etc.. etc.. simple as it can be but not simpler
print('Done...')
finally:
m.logout()
if __name__ == '__main__':
main()
Above will dump your emails to:
D:\my_email\INBOX\msg_no_1.eml ... msg_no203.eml
then you need this secret to open eml's on windows:
Administrator: cmd.com:
assoc .eml=Outlook.File.eml
ftype Outlook.File.eml="C:\Program Files (x86)\Microsoft Office\Office12\OUTLOOK.EXE" /eml "%1"
Dear stockoverflow censor - please be merciful, I would found above useful; for example this: smsg = msg.as_bytes().decode(encoding='ISO-8859-1') took a long to figure out.
To answer your question: after staring at the docs for a long time I didn't see any cleanly way to do what you are looking for. If it is an absolute requirement that the UIDs be stored in the mbox file, then I'd suggest adding a custom UID header to the emails that you are storing:
message = email.message_from_string(lst2[0][1])
message.add_header("my_internal_uid_header", lst1[0][1])
mbox.add(message)
Now of course it is a HUGE pain to get the largest saved UID because you have to iterate through all the messages. I imagine that this would be really bad. If at all possible it would be better to store such information elsewhere.
Best of luck!