im trying to query in mailbox with python3 imap_tools, cant uderstand how to extract emails with sender email and unseen flag. Trying like this
for msg in [msg for msg in mailbox.fetch(Q(from_=sender, seen=False))]
And always get same error
imap_tools.utils.UnexpectedCommandStatusError: Response status for command "box.search" == "NO", "OK" expected, data: [b'[CANNOT] Unsupported search criterion: FROM "ZOYA1608#YANDEX.RU" UNSEEN']
Can somebody explain where my mistake,
full code below
with open("..\\conf\\conf.yaml", mode="r") as stream:
for conf in yaml.safe_load_all(stream):
with MailBox(conf['host']).login(conf['mailbox'], conf['password']) as mailbox:
for sender in conf['senders']['from']:
for msg in [msg for msg in mailbox.fetch(Q(from_=sender, seen=False))]:
for att in msg.attachments:
with open(get_path(file_name=att.filename, store_paths=conf['store_paths']), 'w+b') as f:
f.write(att.payload)
yandex server support From queries
A(from_="ZOYA1608#YANDEX.RU", seen=False) works, I checked
Do not forget update lib sometimes
Most likely: your server doesn't fully support the IMAP search specification.
Regards, imap_tools author.
Related
Test code:
fetch_criteria = AND(seen=False), AND(NOT(uid=['61','88']))
for message in mailbox.fetch(fetch_criteria, mark_seen=False, charset='utf8', limit=10):
print(message.uid)
Server response:
SEARCH command error: BAD [b'Could not parse command']
Please help me correctly create the conditions to exclude emails with UID 66 and 88
from imap_tools import AND, NOT
mailbox.fetch(AND(NOT(uid=['39', '40'])))
mailbox.fetch(NOT(AND(uid=['39', '40'])))
Both works for me at [yandex, google, outlook, zimbra].
May be your server can not do this.
Error example at mail.ru: imap_tools.errors.MailboxSearchError: Response status "OK" expected, but "NO" received. Data: [b'[CANNOT] Unsupported search criterion: (UID 5,6)']
Lib author.
Looking to create and send messages with multiple files attached. Per the online gmail api documentation, there is a function for building messages with an attachment but no documentation for howto use it to create a message with multiple attachments.
Can I use the gmail API to send messages with multiple attachments programmatically? How might one do this?
With this function, you can send to one or multiple recipient emails, and also you can attach zero, one or more files. Coding improvement recommendations are welcome, however the way it is now, it works.
Python v3.7
smtplib from https://github.com/python/cpython/blob/3.7/Lib/smtplib.py (download the code and create the smtplib.py on your project folder)
def send_email(se_from, se_pwd, se_to, se_subject, se_plain_text='', se_html_text='', se_attachments=[]):
""" Send an email with the specifications in parameters
The following youtube channel helped me a lot to build this function:
https://www.youtube.com/watch?v=JRCJ6RtE3xU
How to Send Emails Using Python - Plain Text, Adding Attachments, HTML Emails, and More
Corey Schafer youtube channel
Input:
se_from : email address that will send the email
se_pwd : password for authentication (uses SMTP.SSL for authentication)
se_to : destination email. For various emails, use ['email1#example.com', 'email2#example.com']
se_subject : email subject line
se_plain_text : body text in plain format, in case html is not supported
se_html_text : body text in html format
se_attachments : list of attachments. For various attachments, use ['path1\file1.ext1', 'path2\file2.ext2', 'path3\file3.ext3']. Follow your OS guidelines for directory paths. Empty list ([]) if no attachments
Returns
-------
se_error_code : returns True if email was successful (still need to incorporate exception handling routines)
"""
import smtplib
from email.message import EmailMessage
# Join email parts following smtp structure
msg = EmailMessage()
msg['From'] = se_from
msg['To'] = se_to
msg['Subject'] = se_subject
msg.set_content(se_plain_text)
# Adds the html text only if there is one
if se_html_text != '':
msg.add_alternative("""{}""".format(se_html_text), subtype='html')
# Checks if there are files to be sent in the email
if len(se_attachments) > 0:
# Goes through every file in files list
for file in se_attachments:
with open(file, 'rb') as f:
file_data = f.read()
file_name = f.name
# Attaches the file to the message. Leaves google to detect the application to open it
msg.add_attachment(file_data, maintype='application', subtype='octet-stream', filename=file_name)
# Sends the email that has been built
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
smtp.login(se_from, se_pwd)
smtp.send_message(msg)
return True
Don't forget to activate less secure apps on your google account (https://myaccount.google.com/lesssecureapps) for this code to work.
Hope this helps
I tried to fetch a message content in the following way
result, data = m.uid('fetch', num, "( FLAGS BODY.PEEK[HEADER.FIELDS (SUBJECT FROM DATE)] BODYSTRUCTURE)")
It worked well when I was connecting to a private mail server "mail.example.com"
But it returns exception when I used "imap.gmail.com"
error: UID command error: BAD ['Could not parse command']
I think gmail doesnot support detailed search like HEADER.FIELDS....
So I tried the following option for gmail server and it worked really well
result, data = m.uid('fetch', num, "(FLAGS BODY.PEEK[HEADER] BODYSTRUCTURE)")
I am currently trying to write a script to send off a request token, I have the header, and the claimset, but I don't understand the signature! OAuth requires my private key to be encrypted with SHA256withRSA (also known as RSASSA-PKCS1-V1_5-SIGN with the SHA-256 hash function), but the closest I could find was RSAES-PKCS1-v1_5 (has RSA, and the SHA-256 hash). I followed the example, and tweaked it, so I could get it set, but heres my dillema:
signature = ""
h = SHA.new (signature)
key = RSA.importKey(open('C:\Users\Documents\Library\KEY\My Project 905320c6324f.json').read())
cipher = PKCS1_v1_5.new(key)
ciphertext = cipher.encrypt(message+h.digest())
print(ciphertext)
I'm a bit lost, the JSON file I was given has both public key, and private, do I copy and paste the private key into the signature variable (it gave me a invalid syntax)? Or do I past the directory again? I am so lost, and way over my head haha. I am currently running Python 3.4, with pyCrypto for the signature.
Based on what you've said below about wanting to write a command system using gmail, I wrote a simple script to do this using IMAP. I think this is probably simpler than trying to use Google APIs for a single user, unless you were wanting to do that simply for the exercise.
import imaplib, logging
from time import sleep
USERNAME = 'YOUR_USERNAME_HERE' # For gmail, this is your full email address.
PASSWORD = 'YOUR_PASSWORD_HERE'
CHECK_DELAY = 60 # In seconds
LOGGING_FORMAT = '%(asctime)s %(message)s'
logging.basicConfig(filename='imapTest.log', format=LOGGING_FORMAT, level=logging.INFO)
logging.info("Connecting to IMAP server...")
imap = imaplib.IMAP4_SSL('imap.gmail.com')
imap.login(USERNAME, PASSWORD)
logging.info("Connected to IMAP server.")
def get_command_messages():
logging.info("Checking for new commands.")
imap.check()
# Search the inbox (server-side) for messages containing the subject 'COMMAND' and which are from you.
# Substitute USERNAME below for the sending email address if it differs.
typ, data = imap.search(None, '(FROM "%s" SUBJECT "COMMAND")' %(USERNAME))
return data[0]
def delete_messages(message_nums):
logging.info("Deleting old commands.")
for message in message_nums.split():
imap.store(message, '+FLAGS', '\\DELETED')
imap.expunge()
# Select the inbox
imap.select()
# Delete any messages left over that match commands, so we are starting 'clean'.
# This probably isn't the nicest way to do this, but saves checking the DATE header.
message_nums = get_command_messages()
delete_messages(message_nums)
try:
while True:
sleep(CHECK_DELAY)
# Get the message body and sent time. Use BODY.PEEK instead of BODY if you don't want to mark the message as read, but we're deleting it anyway below.
message_nums = get_command_messages()
if message_nums:
# search returns space-separated message IDs, but we need them comma-separated for fetch.
typ, messages = imap.fetch(message_nums.replace(' ', ','), '(BODY[TEXT])')
logging.info("Found %d commands" %(len(messages[0])))
for message in messages[0]:
# You now have the message body in the message variable.
# From here, you can check against it to perform commands, e.g:
if 'shutdown' in message:
print("I got a shutdown command!")
# Do stuff
delete_messages(message_nums)
finally:
try:
imap.close()
except:
pass
imap.logout()
If you're set on using the Gmail API, though, Google strongly encourage you to use their existing Python library rather than attempt to do full authentication etc. yourself as you appear to be. With that, it should - more or less - be a case of replacing the imap calls above with the relevant Gmail API ones.
I am writing a Python program that can login Gmail.
The purpose of this program is to check whether the username/password combination exists and is correct.
Since this program is to test the the username/password combination existence, it's no need to know any mail contents in Gmail.
The input of this program is a username and password.
The output of this program is either
successful login
or
login failure
Login failure could be:
existing username+wrong password
nonexisting username
My idea is to login Gmail first. Afterward, when login failure, the gmail webpage will show particular message on the login webpage. I can parse the webpage content and check whether it has that particular message.
However, I still have no idea how to login Gmail in Python. Please let me know which module can be used or write me a small piece of sample code.
Here's an idea:
Why don't you try to send an email from the account and see if it sends? You can do this with smtplib in the python standard module. There's code examples here. You'll have to look into the doc of the module, but it looks like an exception is thrown if the login fails, which should contain the details you're interested in.
In edit:
I dug up this bit of code that I wrote to do exactly that. You'll need to put a try/catch around the bit at the bottom to detect erroneous login credentials.
# Subject
now = dt.datetime.now().ctime()
subject = 'Change to system on %s' % now
# Body
body = 'Subject: %s,\n' % subject
body += 'On %s, a change to the system was detected. Details follow.\n\n' % now
relevantFiles = list(set([x.file for x in relevantChunks]))
for file in relevantFiles:
fileChunks = [x for x in relevantChunks if x.file == file]
for chunk in fileChunks:
body += '****** Affected file %s. ' % chunk.file
<some other stuff>
server = smtp.SMTP(args.host) # host = smtp.gmail.com:<port> look this bit up
server.starttls()
server.login(args.username, args.password)
server.sendmail(args.sender, args.recipient, body)
server.quit()
As an aside, I'm not quite sure why this question was down-voted, or even what it takes to be down-voted other than the fact that you asked the wrong question.
try this:
from email.mime.text import MIMEText
import smtplib
msg = MIMEText("Hello There!")
msg['Subject'] = 'A Test Message'
msg['From'] = 'username#gmail.com'
msg['To'] = 'username#gmail.com'
s = smtplib.SMTP('smtp.gmail.com:587')
s.starttls() ##Must start TLS session to port 587 on the gmail server
s.login('username', 'passsword') ##Must pass args gmail username & password in quotes to authenticate on gmail
s.sendmail('username#gmail.com',['username#gmail.com'],msg.as_string())
print("Message Sent")
This kind of things are like prohibited, that's why things like OAuth or OpenID are created. This kind of things permit the user to login without entering username and password. So be careful.