how i get mails from gmail over imap with python - python

This is my script, the auth_string is right, i tryed this smtplib.SMTP('smtp.gmail.com:587') and its worked, imap is activ in my gmail settings, and yes, please help me :)
def command_to_url(command):
return '%s/%s' % (GOOGLE_ACCOUNTS_BASE_URL, command)
def call_refresh_token(client_id, client_secret, refresh_token):
params = {}
params['client_id'] = client_id
params['client_secret'] = client_secret
params['refresh_token'] = refresh_token
params['grant_type'] = 'refresh_token'
request_url = command_to_url('o/oauth2/token')
response = urllib.request.urlopen(request_url, urllib.parse.urlencode(params).encode('UTF-8')).read().decode('UTF-8')
return json.loads(response)
def refresh_authorization(google_client_id, google_client_secret, refresh_token):
response = call_refresh_token(google_client_id, google_client_secret, refresh_token)
return response['access_token'], response['expires_in']
def generate_oauth2_string(username, access_token, as_base64=False):
auth_string = 'user=%s\1auth=Bearer %s\1\1' % (username, access_token)
if as_base64:
auth_string = base64.b64encode(auth_string.encode('ascii')).decode('ascii')
return auth_string
def test_imap(user, auth_string):
imap_conn = imaplib.IMAP4_SSL('imap.gmail.com', port=993)
imap_conn.debug = 4
imap_conn.authenticate('XOAUTH2 ', lambda x: auth_string)
access_token, expires_in = refresh_authorization(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REFRESH_TOKEN)
auth_string = generate_oauth2_string('---------#gmail.com', access_token, as_base64=True)
test_imap('---------#gmail.com', auth_string)
response:
30:07.30 > b'KOHE1 AUTHENTICATE XOAUTH2 '
30:07.32 < b'+ '
30:07.32 write literal size 376
30:07.41 < b'+ eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoiQmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ=='
30:07.41 write literal size 376
30:07.48 < b'KOHE1 BAD Invalid SASL argument. q16mb213626858wmq'
30:07.48 BAD response: b'Invalid SASL argument. q16mb213626858wmq'
Traceback (most recent call last):
File "E:\path_to_script\mail_send.py", line 148, in <module>
test_imap('---------#gmail.com', auth_string)
File "E:\path_to_script\mail_send.py", line 78, in test_imap
imap_conn.authenticate('XOAUTH2 ', lambda x: auth_string)
File "C:\Users\username\AppData\Local\Programs\Python\Python37\lib\imaplib.py", line 428, in authenticate
typ, dat = self._simple_command('AUTHENTICATE', mech)
File "C:\Users\username\AppData\Local\Programs\Python\Python37\lib\imaplib.py", line 1196, in _simple_command
return self._command_complete(name, self._command(name, *args))
File "C:\Users\username\AppData\Local\Programs\Python\Python37\lib\imaplib.py", line 1027, in _command_complete
raise self.error('%s command error: %s %s' % (name, typ, data))
imaplib.error: AUTHENTICATE command error: BAD [b'Invalid SASL argument. q16mb213626858wmq']
I try this since 3 days and i dont anymore :[]

The solution is that my auth_string was as_base64 encoded, but imap wants the 'not encoded' auth_string
access_token, expires_in = refresh_authorization(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REFRESH_TOKEN)
auth_string = generate_oauth2_string('---------#gmail.com', access_token, as_base64=False)
test_imap('---------#gmail.com', auth_string)

Try step by step:
M = imaplib.IMAP4_SSL('imap.gmail.com')
try:
rv, data = M.login(EMAIL_ACCOUNT, EMAIL_PASSWORD)
except imaplib.IMAP4.error:
print "Login failed."
sys.exit(1)
This will test IMAP4_SSL with Gmail against your credentials (without OAUTH2, so verify this configuration to be enabled).
If that works, and XOAUTH2 does not, well clearly I must question your statement that the auth string is correct.
For example, the error you get back seems to refer to a scope of mail.google.com, while I would have expected imap.google.com. Is this correct?
Also, is the extra space after 'XOAUTH2' a typo, or is it in the original code? That might mess with the algo selection mechanism.
You might want to re-start afresh from the Google Python XOAUTH2 sample code and build up from there.

Related

how to fix output error in emailcheck python script

iam trying to use a python script to do listener on gmail to get incoming emails with spicific criteria so far everything work well the script so listener and wait for the expected emai but when the email is recived i goten the following error any help will be welcome iam too beginer . already thanks.
the script used:
import time
from itertools import chain
import email
import imaplib
imap_ssl_host = 'imap.gmail.com' # imap.mail.yahoo.com
imap_ssl_port = 993
username = 'USERNAME or EMAIL ADDRESS'
password = 'PASSWORD'
# Restrict mail search. Be very specific.
# Machine should be very selective to receive messages.
criteria = {
'FROM': 'PRIVILEGED EMAIL ADDRESS',
'SUBJECT': 'SPECIAL SUBJECT LINE',
'BODY': 'SECRET SIGNATURE',
}
uid_max = 0
def search_string(uid_max, criteria):
c = list(map(lambda t: (t[0], '"'+str(t[1])+'"'), criteria.items())) + [('UID', '%d:*' % (uid_max+1))]
return '(%s)' % ' '.join(chain(*c))
# Produce search string in IMAP format:
# e.g. (FROM "me#gmail.com" SUBJECT "abcde" BODY "123456789" UID 9999:*)
def get_first_text_block(msg):
type = msg.get_content_maintype()
if type == 'multipart':
for part in msg.get_payload():
if part.get_content_maintype() == 'text':
return part.get_payload()
elif type == 'text':
return msg.get_payload()
server = imaplib.IMAP4_SSL(imap_ssl_host, imap_ssl_port)
server.login(username, password)
server.select('INBOX')
result, data = server.uid('search', None, search_string(uid_max, criteria))
uids = [int(s) for s in data[0].split()]
if uids:
uid_max = max(uids)
# Initialize `uid_max`. Any UID less than or equal to `uid_max` will be ignored subsequently.
server.logout()
# Keep checking messages ...
# I don't like using IDLE because Yahoo does not support it.
while 1:
# Have to login/logout each time because that's the only way to get fresh results.
server = imaplib.IMAP4_SSL(imap_ssl_host, imap_ssl_port)
server.login(username, password)
server.select('INBOX')
result, data = server.uid('search', None, search_string(uid_max, criteria))
uids = [int(s) for s in data[0].split()]
for uid in uids:
# Have to check again because Gmail sometimes does not obey UID criterion.
if uid > uid_max:
result, data = server.uid('fetch', uid, '(RFC822)') # fetch entire message
msg = email.message_from_string(data[0][1])
uid_max = uid
text = get_first_text_block(msg)
print 'New message :::::::::::::::::::::'
print text
server.logout()
time.sleep(1)
the result:
C:\Users\PC Sony>"C:/Users/PC Sony/AppData/Local/Programs/Python/Python38/python.exe" "c:/Users/PC Sony/Desktop/elzero/elzero/# import PySimpleGUI.py"
Traceback (most recent call last):
File "c:/Users/PC Sony/Desktop/elzero/elzero/# import PySimpleGUI.py", line 68, in <module>
result, data = server.uid('fetch', uid, '(RFC822)') # fetch entire message
File "C:\Users\PC Sony\AppData\Local\Programs\Python\Python38\lib\imaplib.py", line 881, in uid
typ, dat = self._simple_command(name, command, *args)
File "C:\Users\PC Sony\AppData\Local\Programs\Python\Python38\lib\imaplib.py", line 1205, in _simple_command
return self._command_complete(name, self._command(name, *args))
File "C:\Users\PC Sony\AppData\Local\Programs\Python\Python38\lib\imaplib.py", line 963, in _command
data = data + b' ' + arg
TypeError: can't concat int to bytes
result, data = server.uid('fetch', uid, '(RFC822)')
should be changed to
result, data = server.uid('fetch', str(uid), '(RFC822)')
arguments should be of type string or bytes.
source code in imaplib.py
for arg in args:
if arg is None: continue
if isinstance(arg, str):
arg = bytes(arg, "ASCII")
data = data + b' ' + arg

Python Gmail API. socket.timeout - unable to write error when trying to send .log file

I have tried every possible combination in sending a .log file with the Python Gmail API. However, when I do try to create an email message and send as an attachment, I receive a socket.timeout error related to socket writing.
error:
File "C:\Users\MyUser\AppData\Local\Programs\Python\Python38-32\lib\http\client.py", line 1240, in request
self._send_request(method, url, body, headers, encode_chunked)
File "C:\Users\MyUser\AppData\Local\Programs\Python\Python38-32\lib\http\client.py", line 1286, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "C:\Users\MyUser\AppData\Local\Programs\Python\Python38-32\lib\http\client.py", line 1235, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "C:\Users\MyUser\AppData\Local\Programs\Python\Python38-32\lib\http\client.py", line 1045, in _send_output
self.send(chunk)
File "C:\Users\MyUser\AppData\Local\Programs\Python\Python38-32\lib\http\client.py", line 967, in send
self.sock.sendall(data)
File "C:\Users\MyUser\AppData\Local\Programs\Python\Python38-32\lib\ssl.py", line 1204, in sendall
v = self.send(byte_view[count:])
File "C:\Users\MyUser\AppData\Local\Programs\Python\Python38-32\lib\ssl.py", line 1173, in send
return self._sslobj.write(data)
socket.timeout: The write operation timed out
I use this function to create an email. I return a list of two different emails. The first email is the email with attachments. The second email is without attachments. I send the email without attachments when the email with attachments fails.
Create email:
def createMessage(self, sender , to, subject, messageBody, attachmentList):
try:
message = MIMEMultipart()
message['to'] = to
message['from'] = sender
message['subject'] = subject
msg = MIMEText(messageBody)
message.attach(msg)
raw_message = base64.urlsafe_b64encode(message.as_string().encode("utf-8"))
regularMessage = {'raw' : raw_message.decode("utf-8")}
totalSizeOf = 0
for targetAttachment in attachmentList:
targetAttachmentExtension = targetAttachment.getFileExtension()
if targetAttachmentExtension is False:
logging.error("Failed to get target attachment extension.")
continue
targetAttachmentFileInstance = targetAttachment.getFileInstance()
if targetAttachmentFileInstance is False:
logging.error("Failed to get file instance.")
continue
attachmentSizeBytes = sys.getsizeof(targetAttachmentFileInstance)
if totalSizeOf + attachmentSizeBytes > 5000000:
continue
else:
totalSizeOf = totalSizeOf + attachmentSizeBytes
if targetAttachmentExtension == 'jpg':
msgAttachment = MIMEImage(targetAttachmentFileInstance, _subtype='jpeg')
elif targetAttachmentExtension == 'png':
msgAttachment = MIMEImage(targetAttachmentFileInstance, _subtype='png')
elif targetAttachmentExtension == 'txt' or targetAttachmentExtension =='log':
if type(targetAttachmentFileInstance) is bytes:
targetAttachmentFileInstance = targetAttachmentFileInstance.decode('utf-8')
msgAttachment = MIMEText(targetAttachmentFileInstance, _subtype='plain')
else:
msgAttachment = MIMEBase('application', 'octet-stream')
msgAttachment.set_payload(targetAttachmentFileInstance)
targetAttachmentFileName = targetAttachment.getFullFilename()
if targetAttachmentFileName is False:
logging.error("Failed to get attachment filename")
continue
msgAttachment.add_header('Content-Disposition', 'attachment', filename=targetAttachmentFileName)
message.attach(msgAttachment)
raw = base64.urlsafe_b64encode(message.as_bytes())
raw = raw.decode()
attachmentMessage = {'raw' : raw}
return [attachmentMessage, regularMessage]
except:
self.GLogger.error("An error was encountered while attempting create an email message")
tb = traceback.format_exc()
self.GLogger.exception(tb)
return False
Send Function:
def gmailAPISendEmailAttachmentFailover(self, message, userID="me"):
try:
service = self.gmailAPIService
self.GLogger.info("Attempting to send email message")
if type(message) != list:
self.GLogger.error(f"Expected the message to be of type list")
return False
if len(message) != 2:
self.GLogger.error("Message list length not 2")
return False
attachmentMessage = message[0]
regularMessage = message[1]
try:
response = (service.users().messages().send(userId=userID, body=attachmentMessage).execute())
except:
response = (service.users().messages().send(userId=userID, body=regularMessage).execute())
responseID = str(response['id'])
self.GLogger.info("Successfully sent email message with ID (" + responseID +")")
return responseID
except:
self.GLogger.error("Failed to send email message")
tb = traceback.format_exc()
self.GLogger.exception(tb)
return False
The attachmentList is a list of Attachment Objects. The only significance of this is that I have tried reading the .log files into the Attachment object as 'rb' and 'r'. Simply fileinstance=FID.read(). I tried sending the log file as main_type = application and sub_type = octet-stream. I have also tried sending it as MIMEText with a sub_type = plain.
As you can see in my create email function, I am also currently limiting the attachment size to 5MB. I reduced it from 15 MB since I was thinking that might have been the problem.
I'm completely stumped why it does not work. Please help.

TypeError in XMLRPC client

I am trying to consume services from a XMLRPC web service using python.
The remote web server require authentication and ssl verification. To do this staff, I implemented a an xmlrpc client using xmlrpc.client as follows:
class HTTPSDigestAuthTransport:
def request(self, host, handler, request_body, verbose=0):
api_url = Setup.get_api_url()
username = Setup.get_api_username()
password = Setup.get_api_password()
h = httplib2.Http()
if verbose:
h.debuglevel = 1
h.add_credentials(username, password)
h.disable_ssl_certificate_validation = True
resp, content = h.request("https://" + api_url, "POST", body=request_body,
headers={'content-type': 'text/xml'})
if resp.status != 200:
raise ProtocolError("https://" + api_url, resp.status, resp.reason, None)
p, u = getparser(0)
p.feed(content)
# transport factory instance
transport = HTTPSDigestAuthTransport()
# url composition
url = "https://" + Setup.get_api_username() + ":" + Setup.get_api_password() + "#" + Setup.get_api_url()
# create the proxy
proxy = xmlrpc.client.ServerProxy(url, transport)
res = proxy.do_some_work()
The problem is that the instruction res = proxy.do_some_work() generates this error:
File "/usr/lib/python3.6/xmlrpc/client.py", line 1112, in __call__
return self.__send(self.__name, args)
File "/usr/lib/python3.6/xmlrpc/client.py", line 1455, in __request
if len(response) == 1:
TypeError: object of type 'NoneType' has no len()
Is object of type 'NoneType' has no len() due the the response format? What can be the solution?

Gnip issue - while creating a job -- urllib2.URLError

I am trying to create a job using Gnip Historical Powertrack API.
I am getting issue with the urllib..
import urllib2
import base64
import json
UN = '' # YOUR GNIP ACCOUNT EMAIL ID
PWD = ''
account = '' # YOUR GNIP ACCOUNT USER NAME
def get_json(data):
return json.loads(data.strip())
def post():
url = 'https://historical.gnip.com/accounts/' + account + '/jobs.json'
publisher = "twitter"
streamType = "track"
dataFormat = "activity-streams"
fromDate = "201510140630"
toDate = "201510140631"
jobTitle = "job30"
rules = '[{"value":"","tag":""}]'
jobString = '{"publisher":"' + publisher + '","streamType":"' + streamType + '","dataFormat":"' + dataFormat + '","fromDate":"' + fromDate + '","toDate":"' + toDate + '","title":"' + jobTitle + '","rules":' + rules + '}'
base64string = base64.encodestring('%s:%s' % (UN, PWD)).replace('\n', '')
req = urllib2.Request(url=url, data=jobString)
req.add_header('Content-type', 'application/json')
req.add_header("Authorization", "Basic %s" % base64string)
proxy = urllib2.ProxyHandler({'http': 'http://proxy:8080', 'https': 'https://proxy:8080'})
opener = urllib2.build_opener(proxy)
urllib2.install_opener(opener)
try:
response = urllib2.urlopen(req)
the_page = response.read()
the_page = get_json(the_page)
print 'Job has been created.'
print 'Job UUID : ' + the_page['jobURL'].split("/")[-1].split(".")[0]
except urllib2.HTTPError as e:
print e.read()
if __name__=='__main__':
post()
this is the error I am getting :
Traceback (most recent call last):
File "gnip1.py", line 37, in <module>
post()
File "gnip1.py", line 28, in post
response = urllib2.urlopen(req)
File "/home/soundarya/anaconda-new-1/lib/python2.7/urllib2.py", line 154, in urlopen
return opener.open(url, data, timeout)
File "/home/soundarya/anaconda-new-1/lib/python2.7/urllib2.py", line 431, in open
response = self._open(req, data)
File "/home/soundarya/anaconda-new-1/lib/python2.7/urllib2.py", line 449, in _open
'_open', req)
File "/home/soundarya/anaconda-new-1/lib/python2.7/urllib2.py", line 409, in _call_chain
result = func(*args)
File "/home/soundarya/anaconda-new-1/lib/python2.7/urllib2.py", line 1240, in https_open
context=self._context)
File "/home/soundarya/anaconda-new-1/lib/python2.7/urllib2.py", line 1197, in do_open
raise URLError(err)
urllib2.URLError: <urlopen error [Errno -2] Name or service not known>
I even tried through the curl command:
When I tried running the below one in terminal, I am getting error - ServiceUsername is not valid.
curl -v -X POST -uname -d '{"title": "HPT_test_job","publisher": "Twitter","streamType":"track","dataFormat":"activity-streams","fromDate":"201401010000","toDate":"201401020000 ","rules":[{"value": "twitter_lang:en (Hillary Clinton OR Donald)","tag": "2014_01_01_snow"}]}' 'https://historical.gnip.com/accounts/account_name/jobs.json'
This is the exact output msg:
Error retrieving Job status: {u'serviceUsername': [u'is invalid']} -- Please verify your connection parameters and network connection *
Try this.. see if it helps
import urllib2
from urllib2.request import urlopen
u = urlopen ('http:// .........')
If you are using python 3.5 you should use the library urllib.request which is the newer version of urllib2. Notice however that this changes a few things in the code including print (which should be in parentheses) and the need to transform some of the string results into bytes. Here you can look at all the required changes in code adapted to python 3.5

IMAP search not finding new email

My test code sends an email with an attachment and saves a hash that is in the subject and body. I then have a function that takes the hash searches for it, gets the uid and fetches the email returning the attachment data.
The problem I am having is when I send a message and then subsequently search for the hash the email server says there is no matching uid, however if I run another copy of the script it does find it! Even if the second script is ran first! It first finds it but the original one doesn't; even though it is later!
Output
$ python test_server_file_functions.py
Creating mail server
S: '* OK Gimap ready for requests from [ip] [data]'
C: '0001 CAPABILITY'
S: '* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH AUTH=XOAUTH2'
S: '0001 OK Thats all she wrote! [data]'
C: '0002 LOGIN "user#gmail.com" "password"'
S: '* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 UIDPLUS COMPRESS=DEFLATE ENABLE MOVE'
S: '0002 OK user#gmail.com Anonymous Test authenticated (Success)'
C: '0003 SELECT INBOX'
S: '* FLAGS (\\Answered \\Flagged \\Draft \\Deleted \\Seen)'
S: '* OK [PERMANENTFLAGS (\\Answered \\Flagged \\Draft \\Deleted \\Seen \\*)] Flags permitted.'
S: '* OK [UIDVALIDITY 1] UIDs valid.'
S: '* 0 EXISTS'
S: '* 0 RECENT'
S: '* OK [UIDNEXT 132] Predicted next UID.'
S: '0003 OK [READ-WRITE] INBOX selected. (Success)'
Does not exists
Created mail server
Sending email
Sent email
Waiting 3 minutes to make sure it isn't a simple delay with the email being relayed
Downloading Data...
C: '0004 SEARCH SUBJECT "EMS Data ID: 622904923b1825d5742ed25fb792fafe2e710c40ceea09660a604be8fabac35ae9b006c43c7a992159b8b0df376383830a6d4c54ed5b141c8429a4feec89cd8b"'
S: '* SEARCH'
S: '0004 OK SEARCH completed (Success)'
Unhandled Error
Traceback (most recent call last):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/mail/imap4.py", line 2455, in _defaultHandler
cmd.finish(rest, self._extraInfo)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/mail/imap4.py", line 382, in finish
d.callback((send, lastLine))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/defer.py", line 368, in callback
self._startRunCallbacks(result)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/defer.py", line 464, in _startRunCallbacks
self._runCallbacks()
--- <exception caught here> ---
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/defer.py", line 551, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File "/Users/user/Documents/gms/gms/mail_backend.py", line 178, in process_download_uid
raise IOError("Hash not found, however database indicates it was uploaded")
exceptions.IOError: Hash not found, however database indicates it was uploaded
There was an error retrieving the email
Traceback (most recent call last):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/mail/imap4.py", line 2455, in _defaultHandler
cmd.finish(rest, self._extraInfo)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/mail/imap4.py", line 382, in finish
d.callback((send, lastLine))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/defer.py", line 368, in callback
self._startRunCallbacks(result)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/defer.py", line 464, in _startRunCallbacks
self._runCallbacks()
--- <exception caught here> ---
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/defer.py", line 551, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File "/Users/user/Documents/gms/gms/mail_backend.py", line 178, in process_download_uid
raise IOError("Hash not found, however database indicates it was uploaded")
exceptions.IOError: Hash not found, however database indicates it was uploaded
Quiting...
Code
import os
# logging
from twisted.python import log
import sys
import time
import email
from Utils import BLOCK
# IMAP
from IMAPBackend import connectToIMAPServer, Command
# SMTP
from SMTPBackend import connectToSMTPServer
# Hash Database
from HashDatabase import HashDatabase, hash
# deferreds
from twisted.internet.defer import Deferred, DeferredList, succeed
from twisted.internet.task import deferLater
#reactor
from twisted.internet import reactor
BLOCK_SIZE = BLOCK / 1024 # convert from bytes (needed for FTP) to kilobytes
def createMailServer(username, password, smtp_server, imap_server, hash_db = "hash.db"):
# create smtp connection
smtp_d = connectToSMTPServer(smtp_server, username, password)
# create imap connection
imap_d = connectToIMAPServer(imap_server, username, password)
dl = DeferredList([smtp_d, imap_d])
dl.addCallback(lambda r: [ MailServer(r[0][1], r[1][1], username, hash_db) ][0] )
return dl
class ServerManager(object):
def __init__(self, mail_servers):
self.mail_servers = mail_servers
def get_server(self, accnt):
for ms in self.mail_servers:
if ms.account == accnt:
return succeed(ms)
def return_server(self):
# retrieve the size avialable on the servers
get_space_deferreds = []
for ms in self.mail_servers:
d = ms.get_space()
d.addCallback(lambda r: (ms, r))
get_space_deferreds.append(d)
dl = DeferredList(get_space_deferreds, consumeErrors = True)
dl.addCallback(self.parse_sizes)
return dl
def parse_sizes(self, results):
for no_error, result in results:
server = result[0]
result = result[1]
if no_error:# not an error so a potential server
for argument in result[0]:
if argument[0] == "QUOTA":
print "Argument"
print argument
print "/Argument"
used, total = argument[2][1:3]
available_kb = int(total) - int(used)
if available_kb > BLOCK_SIZE:# server with more then our block size
return server
else:
print "Error from account %s" % server.email_address
# no free space was found :-(
raise IOError("No free space was found.")
class MailServer(object):
"Manages a server"
size = 0
used_space = 0
def __init__(self, smtp_connection, imap_connection, email_address, hash_db = "hash.db"):
self.smtp_connection = smtp_connection
self.imap_connection = imap_connection
self.hash_database = HashDatabase(hash_db)
self.email_address = email_address
self.account = email_address
# current uploads
self.current_uploads = {}
# current downloads
self.current_downloads = {}
def get_space(self):
cmd = Command("GETQUOTAROOT", "INBOX", ["QUOTAROOT", "QUOTA"])
d = self.imap_connection.sendCommand(cmd)
return d
def upload_data(self, data):
"""
Uploads data to email server returns deferred that will return with the imap uid
"""
data_hash = hash(data)
if data_hash in self.current_uploads:
d = Deferred()
self.current_uploads[data_hash].append(d)
return d
if self.hash_database.hash_in_list(data_hash):
print "Data hash is in the database; not uploading"
return succeed(data_hash)
else:
d = Deferred()
self.current_uploads[data_hash] = [d]
id = "EMS Data ID: %s" % data_hash
connection_deferred = self.smtp_connection.send_email(self.email_address, self.email_address, id, id, [["raw_ems", "ems.dat", data] ])
connection_deferred.addCallback(self.upload_success, data_hash)
connection_deferred.addErrback(self.upload_error, data_hash)
connection_deferred.addBoth(self.notify_uploaders, data_hash)
return d
def notify_uploaders(self, result, data_hash):
for waitingDeferred in self.current_uploads.pop(data_hash):
# if r is a Failure, this is equivalent to calling .errback with
# that Failure.
waitingDeferred.callback(result)
def upload_success(self, result, data_hash):
# add to hash table
self.hash_database.add_hash(data_hash)
# immediatly searching doesn't seem to work so search on data retrieval
return data_hash
def upload_error(self, error, data_hash):
# upload error
log.msg("Erroring uploading file")
log.err(error)
return error # send error to uploader
def download_data(self, data_hash):
"""
Downloads data from the email server returns a deferred that will return with the data
"""
d = Deferred()
if data_hash in self.current_downloads:
self.current_downloads[data_hash].append(d)
return d
if not self.hash_database.hash_in_list(data_hash):
print "Data Hash has never been uploaded..."
raise IOError("No such data hash exists")
else:
self.current_downloads[data_hash] = [d]
id = "EMS Data ID: %s" % data_hash
connection_deferred = self.imap_connection.search("SUBJECT", "\"EMS Data ID: %s\"" % data_hash, uid = False)
connection_deferred.addCallback(self.process_download_uid)
connection_deferred.addErrback(self.download_error, data_hash)
connection_deferred.addBoth(self.notify_downloaders, data_hash)
return d
return d
def process_download_uid(self, id):
if len(id) == 0:
raise IOError("Hash not found, however database indicates it was uploaded")
d = self.imap_connection.fetchMessage(id[-1])
d.addCallback(self.process_download_attachment, id[-1])
return d
def process_download_attachment(self, data, id):
email_text = data[id]["RFC822"]
msg = email.message_from_string(email_text)
for part in msg.walk():
type = part.get_content_type()
print repr(type)
if "raw_ems" in type:
log.msg("Found Payload")
return part.get_payload(decode = True)
log.msg("No attachment found")
raise IOError("Data not found")
def download_error(self, error, data_hash):
log.msg("Error downloading file")
log.err(error)
return error
def notify_downloaders(self, result, data_hash):
for waitingDeferred in self.current_downloads.pop(data_hash):
# if r is a Failure, this is equivalent to calling .errback with
# that Failure.
waitingDeferred.callback(result)
def delete_data(self, data_hash):
if not self.hash_database.hash_in_list(data_hash):
raise IOError("No such data hash uploaded")
else:
# delete it to prevent anyone from trying to download it while it is being deleted
self.hash_database.delete_hash(data_hash)
d = self.imap_connection.search("SUBJECT", "\"EMS Data ID: %s\"" % data_hash, uid = False)
d.addCallback(self.delete_message)
d.addErrback(self.deletion_error, data_hash)
return d
def deletion_error(self, error, data_hash):
print "Deletion Error"
log.err(error)
# restore hash to database
self.hash_database.add_hash(data_hash)
raise IOError("Couldn't delete message hash")
def delete_message(self, id):
if len(id) == 0:
raise IOError("Hash not found, however database indicates it was uploaded")
d = self.imap_connection.setFlags(id[-1], ["\\Deleted"])
d.addCallback(lambda result: self.imap_connection.expunge())
return d
## Main Code ##
if __name__ == "__main__":
def deleted_email(result):
print "Deleted the email succesfully"
print "====Result===="
print result
print "====Result===="
print "Quiting..."
os._exit(0)
def error_deleting(error):
print "There was an error deleting the email"
error.printTraceback()
print "Quiting..."
os._exit(0)
def retrieved_data(result, ms, hash):
print "Retrieved data"
print "=====Data===="
print result
print "Deleting email"
d = ms.delete_data(hash)
d.addCallback(deleted_email)
d.addErrback(error_deleting)
return d
def email_retrieval_error(error):
print "There was an error retrieving the email"
error.printTraceback()
print "Quiting..."
os._exit(0)
def sent_email(hash, ms):
print "Sent email"
print "Waiting 3 minutes to make sure it isn't a simple delay with the email being relayed"
time.sleep(3 * 60)
print "Downloading Data..."
d = ms.download_data(hash)
d.addCallback(retrieved_data, ms, hash)
d.addErrback(email_retrieval_error)
return d
def email_sending_error(error):
print "There was an error sending the email"
error.printTraceback()
print "Quiting..."
os._exit(0)
def mail_server_created(ms):
# created mail server
print "Created mail server"
print "Sending email"
d = ms.upload_data("this is the attachment data I am sending to my email account")
d.addCallback(sent_email, ms)
d.addErrback(email_sending_error)
return d
def mail_server_error(error):
print "Error creating mail server"
error.printTraceback()
print "Quiting..."
os._exit(0)
# create mail server object
print "Creating mail server"
d = createMailServer("user#gmail.com", "password", "smtp.gmail.com:587", "imap.gmail.com:993", hash_db = "testhash.db")
d.addCallback(mail_server_created)
d.addCallback(mail_server_error)
from twisted.internet import reactor
reactor.run()
I am thinking I may have to re-select the mailbox? I look in the RFC3501 select and search commands and found nothing about such a problem
Search command works on the data which is collected by parsing the entire mail folder which is been selected by Select command
You will have to select the mail folder again to get the mail entry updated.
Search result will not have the new mail input unless the server has implemented the IDLE/NOOP functionality (again it solely depends on mail server)

Categories

Resources