I have a list of emails(mine) that I want to test against a list of passwords(All valid and some none valid of course) using imaplib library. Whenever I test the program ordinarily like in the code below, it works perfectly no errors.
import sys
import imaplib
# connect to host using SSL
imap_host = 'imap.server.com'
imap_port = '993'
imap_user = 'username#email'
imap_pass = 'RightPassword'
imap = imaplib.IMAP4_SSL(imap_host, imap_port)
## login to server
try:
login = imap.login(imap_user, imap_pass)
if login:
print login
except imaplib.IMAP4.error as error:
print error
#
But whenever I run the code such as to parsing credentials through a function to handle the authentication protocols such as the following code below, I get an error saying
"LOGIN command error: BAD ['Missing \'"\'']".
I have tried all sort of things I could find using google and non seem to handle it properly.
"""
E-mail Tester
NB: This is for educational purpose only.
"""
import sys
import imaplib
EMAILS_FILE = open('email_list.txt', 'r')
PASSWORD_FILE = open('pass_list.txt', 'r')
SUCCESS_FILE = open('success.txt', 'a')
EMAILS_FILE_LIST = []
def set_check(_emails):
email = str(_emails)
PASSWORD_FILE.seek(0)
for passwords in PASSWORD_FILE:
password = str(passwords)
# connect to host using SSL
imap_host = 'imap.server.com'
imap_port = '993'
imap = imaplib.IMAP4_SSL(imap_host, imap_port)
## login to server
try:
# print "%s%s" % (email,password)
# print "I got here so far"
# sys.exit()
print "Testing <--> E-mail: %s - Password: %s" % (email, password)
login = imap.login("%s","%s" % (email, password))
if login:
print login
print "OK <---> E-mail: %s\nPassword: %s" % (email, password)
except imaplib.IMAP4.error as error:
print error
for emails in EMAILS_FILE:
EMAILS_FILE_LIST.append(emails)
for email_count in range(0, len(EMAILS_FILE_LIST)):
set_check(EMAILS_FILE_LIST[email_count])
I have tried all kind of suggestions I could find on the internet but non has worked thus far.
I expect imap.login to handle the authentication without the mysterious error output
"LOGIN command error: BAD ['Missing \'"\'']"
login = imap.login("%s","%s" % (email, password))
does not work. It throws an error in Python: TypeError: not all arguments converted during string formatting, because you're providing two strings to one %s.
Why don't you just use imap.login(email, password)? It has the same effect as what you're trying to do.
And what does your password file look like? What is it actually sending? Please provide the log line before it crashes. (anonymizing if necessary, but leaving any punctuation in for help diagnosing)
Okay, so I actually got this fixed by removing trail lines from my strings.
email = str(_emails).rstrip()
PASSWORD_FILE.seek(0)
for passwords in PASSWORD_FILE:
password = str(passwords).rstrip()
the error is caused by trail lines in the strings.
Related
So, I am trying to run a search with ldap, and trying to check if I am able to initialize it first. However, I keep getting the error {'desc': 'No such object'} I even tried wrong credentials but I don't even get to that error message. If someone could shed light on this, it'd be really helpful. Thanks in advance!
#!/usr/bin/python
import os, os.path
import subprocess as sp
import ldap
l = ldap.initialize('ldap://ldap.domain.com')
username = "uid=%s,ou=People,dc=domain,dc=com"
password = "password"
try:
l.protocol_version = ldap.VERSION3
l.simple_bind_s(username, password)
valid = True
except Exception, error:
print error
except ldap.INVALID_CREDENTIALS:
print "Your username or password is incorrect."
sys.exit(0)
I was getting the same error.
A quick and dirty fix to successfully bind is to change the username variable:
username = "user#domain.com"
the problem with your variable is that the %s is a string formatting syntax (which it borrows from C).
the proper use of that variable would look something like:
username = "uid=%s,ou=People,dc=domain,dc=com" %('insert-username-here')
I'm trying to scrape data from a specific folder in a Gmail account I have access to.
I recently tried running this code using Python 2.7 on Windows 7 while logged into the Gmail account of interest. For some reason though it seems to run for a long time (I left it for as long as 40 minutes) without completing or providing an error.
As it stands right now the folder I'm targeting in the Gmail account only has about 50 simple text emails with no attachments, pictures, or anything that might suggest the process should take as long as it does. Has anyone come across an issue like this before doing something similar with IMAP?
Code for completeness:
#!/usr/bin/env python
#
# Very simple Python script to dump all emails in an IMAP folder to files.
# This code is released into the public domain.
#
# RKI Nov 2013
#
import sys
import imaplib
import getpass
IMAP_SERVER = 'imap.gmail.com'
EMAIL_ACCOUNT = "notatallawhistleblowerIswear#gmail.com"
EMAIL_FOLDER = "Top Secret/PRISM Documents"
OUTPUT_DIRECTORY = 'C:/src/tmp'
PASSWORD = getpass.getpass()
def process_mailbox(M):
"""
Dump all emails in the folder to files in output directory.
"""
rv, data = M.search(None, "ALL")
if rv != 'OK':
print "No messages found!"
return
for num in data[0].split():
rv, data = M.fetch(num, '(RFC822)')
if rv != 'OK':
print "ERROR getting message", num
return
print "Writing message ", num
f = open('%s/%s.eml' %(OUTPUT_DIRECTORY, num), 'wb')
f.write(data[0][1])
f.close()
def main():
M = imaplib.IMAP4_SSL(IMAP_SERVER)
M.login(EMAIL_ACCOUNT, PASSWORD)
rv, data = M.select(EMAIL_FOLDER)
if rv == 'OK':
print "Processing mailbox: ", EMAIL_FOLDER
process_mailbox(M)
M.close()
else:
print "ERROR: Unable to open mailbox ", rv
M.logout()
if __name__ == "__main__":
main()
The code works fine for me. Below, I have added some debug prints to your code (using pprint) to view the attributes of the IMAP4_SSL object M. My Gmail uses two factor authentication so I needed to setup a gmail app password
from pprint import pprint
# ....
M = imaplib.IMAP4_SSL(IMAP_SERVER)
print('---- Attributes of the IMAP4_SSL connection before login ----')
pprint(vars(M))
M.login(EMAIL_ACCOUNT, PASSWORD)
print('\n \n')
print('---- Attributes of the IMAP4_SSL connection after login ----')
pprint(vars(M))
# open specific folder
rv, data = M.select(EMAIL_FOLDER)
print('\n \n')
print('---- Data returned from select of folder = {}'.format(data))
Check the first pprint(vars(M)) for:
'welcome': '\* OK Gimap ready for requests from ...
'port': 993,
Check the second pprint(vars(M)) for:
_cmd_log for a successful login: 6: ('< PJIL1 OK **#gmail.com authenticated (Success)
data returned from M.select(EMAIL_FOLDER) should be the number of emails available to download.
I want to execute the following query in the ldap
ldapsearch -h hostname -b dc=ernet,dc=in -x "(&(uid=w2lame)(objectClass=posixAccount))" gidnumber
ldapsearch -h hostname -b dc=ernet,dc=in -x "(&(gidNumber=1234)(objectClass=posixGroup))" cn
And use the variables thus obtained. How can I do that?
While the accepted answer does in fact show a proper way to bind to an LDAP server I do feel it didn't answer the question holistically. Here is what I ended up implementing to grab the mail and department of a user. This somewhat blends the required attributes from the original question.
l = ldap.initialize('ldap://ldap.myserver.com:389')
binddn = "cn=myUserName,ou=GenericID,dc=my,dc=company,dc=com"
pw = "myPassword"
basedn = "ou=UserUnits,dc=my,dc=company,dc=com"
searchFilter = "(&(gidNumber=123456)(objectClass=posixAccount))"
searchAttribute = ["mail","department"]
#this will scope the entire subtree under UserUnits
searchScope = ldap.SCOPE_SUBTREE
#Bind to the server
try:
l.protocol_version = ldap.VERSION3
l.simple_bind_s(binddn, pw)
except ldap.INVALID_CREDENTIALS:
print "Your username or password is incorrect."
sys.exit(0)
except ldap.LDAPError, e:
if type(e.message) == dict and e.message.has_key('desc'):
print e.message['desc']
else:
print e
sys.exit(0)
try:
ldap_result_id = l.search(basedn, searchScope, searchFilter, searchAttribute)
result_set = []
while 1:
result_type, result_data = l.result(ldap_result_id, 0)
if (result_data == []):
break
else:
## if you are expecting multiple results you can append them
## otherwise you can just wait until the initial result and break out
if result_type == ldap.RES_SEARCH_ENTRY:
result_set.append(result_data)
print result_set
except ldap.LDAPError, e:
print e
l.unbind_s()
You probably want to use the ldap module. Code would look something like:
import ldap
l = ldap.initialize('ldap://ldapserver')
username = "uid=%s,ou=People,dc=mydotcom,dc=com" % username
password = "my password"
try:
l.protocol_version = ldap.VERSION3
l.simple_bind_s(username, password)
valid = True
except Exception, error:
print error
Here's an example generator for python-ldap.
The ldap_server is the object you get from ldap.initialize(). You will probably need to bind before calling this function, too, depending on what LDAP server you are using and what you are trying to query for. The base_dn and filter_ are similar to what you've got in your command line version. The limit is the maximum number of records returned.
def _ldap_list(ldap_server, base_dn, filter_, limit=0):
""" Generator: get a list of search results from LDAP asynchronously. """
ldap_attributes = ["*"] # List of attributes that you want to fetch.
result_id = ldap_server.search(base_dn, ldap.SCOPE_SUBTREE, filter_, ldap_attributes)
records = 0
while 1:
records += 1
if limit != 0 and records > limit:
break
try:
result_type, result_data = ldap_server.result(result_id, 0)
except ldap.NO_SUCH_OBJECT:
raise DirectoryError("Distinguished name (%s) does not exist." % base_dn)
if result_type == ldap.RES_SEARCH_ENTRY:
dn = result_data[0][0]
data = result_data[0][1]
yield dn, data
else:
break
Please keep in mind that interpolating user-provided values into your LDAP query is dangerous! It's a form of injection that allows a malicious user to change the meaning of the query. See: http://www.python-ldap.org/doc/html/ldap-filter.html
I cobbled this together this morning while skimming through the documentation of the ldap module. It can fulfil the requirements of the OP changing the filter and the other settings to his liking.
The documentation of the ldap module is pretty good if you understand the context (that's what took me a while). And the module is surprinsingly easy to use. We have a similar script written in bash using ldapserach that is at least 3 or 4 times longer and more complex to read.
This code accepts a partial search string (email, name, uid or part of it) and returns the results in LDIF format. The idea is to make it very simple to use for a very specific task and if possible without using flags so that my less skilled co-workers can find the relevant info quickly.
Note that this is written for an LDAP server that runs on a machine that is not accessible from outside our internal network and which is secured with 2FA authentication. It can, thus, safely accept anonymous queries. But adding user and password should be trivial.
#! /usr/bin/python3
### usearch
### searches in the LDAP database for part of a name, uid or email and returns mail, uid, and full name
import ldap
import argparse
import sys
import ldif
l = ldap.initialize('ldaps://your.fancy.server.url', bytes_mode=False)
basedn = "dc=foo,dc=bar,dc=baz"
## ARGPARSE stuff!!!
parser=argparse.ArgumentParser(
description ='searches the LDAP server',
usage='usearch PARTIAL_MATCH (email, name, username)',
formatter_class = argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('istr', help='searches stuffz')
parser.print_help
args = parser.parse_args(None if sys.argv[1:] else ['-h'])
str1 = args.istr
sfilter = "(|(sn=*{}*)(mail=*{}*)(uid=*{}*))".format(str1,str1,str1)
attributes = ["mail","uid","cn"]
scope = ldap.SCOPE_SUBTREE
r = l.search_s(basedn,scope,sfilter,attributes)
ldif_writer=ldif.LDIFWriter(sys.stdout)
for dn, entry in r:
ldif_writer.unparse(dn,entry)
And as I was at it, here a version with the ldap3 module. The argparse part is copy-pasted. This time the output is "human readable", instead of LDIF:
#! /usr/bin/python3
## usearch3
## LDAP3 version
import ldap3
import argparse
import sys
server = ldap3.Server('ldaps://foo.bar.baz')
conn = ldap3.Connection(server)
conn.bind()
basedn = 'dc=foobar,dc=dorq,dc=baz'
attribs = ['mail','uid','cn']
parser=argparse.ArgumentParser(
description ='searches the LDAP server and returns user, full name and email. Accepts any partial entry',
usage='usearch3 PARTIAL_MATCH (email, name, username)',
formatter_class = argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('istr', help='searches stuffz')
parser.print_help
args = parser.parse_args(None if sys.argv[1:] else ['-h'])
str1 = args.istr
sfilter = "(|(sn=*{}*)(mail=*{}*)(uid=*{}*))".format(str1,str1,str1)
conn.search(basedn,sfilter)
conn.search(basedn,sfilter,attributes = attribs)
leng = len(conn.entries)
for i in range(leng):
user = conn.entries[i].uid
fullname = conn.entries[i].cn
email = conn.entries[i].mail
print("user:\t{}\nname:\t{}\nemail:\t{}\n\n".format(user,fullname,email))
you can use the commands module, and the getoutput to parse the result of the ldap query:
from commands import getoutput
result = getoutput('ldapsearch -h hostname -b dc=ernet,dc=in -x "(&(uid=w2lame)(objectClass=posixAccount))"')
print result
you have to have ldapsearch binary installed in your system.
I'd like to be able to retrieve a users Google Talk Status Message with Python, it's really hard to find documentation on how to use some of the libraries out there.
I don't have anything to hand with xmpp installed, but here's some old code I had lying around that might help you. You'll want to update the USERNAME/PASSWORD to your own values for test purposes.
Things to note: users logged in to Google Talk get a random presence string on their userid: that doesn't matter if you are trying to get the status of some other user, but if you want to write some code so want to communicate with yourself you need to distinguish the user logged in from GMail or a GTalk client from the test program. Hence the code searches through the userids.
Also, if you read the status immediately after logging in you probably won't get anything. There's a delay in the code because it takes a little while for the status to become available.
"""Send a single GTalk message to myself"""
import xmpp
import time
_SERVER = 'talk.google.com', 5223
USERNAME = 'someuser#gmail.com'
PASSWORD = 'whatever'
def sendMessage(tojid, text, username=USERNAME, password=PASSWORD):
jid = xmpp.protocol.JID(username)
client = xmpp.Client(jid.getDomain(), debug=[])
#self.client.RegisterHandler('message', self.message_cb)
if not client:
print 'Connection failed!'
return
con = client.connect(server=_SERVER)
print 'connected with', con
auth = client.auth(jid.getNode(), password, 'botty')
if not auth:
print 'Authentication failed!'
return
client.RegisterHandler('message', message_cb)
roster = client.getRoster()
client.sendInitPresence()
if '/' in tojid:
tail = tojid.split('/')[-1]
t = time.time() + 1
while time.time() < t:
client.Process(1)
time.sleep(0.1)
if [ res for res in roster.getResources(tojid) if res.startswith(tail) ]:
break
for res in roster.getResources(tojid):
if res.startswith(tail):
tojid = tojid.split('/', 1)[0] + '/' + res
print "sending to", tojid
id = client.send(xmpp.protocol.Message(tojid, text))
t = time.time() + 1
while time.time() < t:
client.Process(1)
time.sleep(0.1)
print "status", roster.getStatus(tojid)
print "show", roster.getShow(tojid)
print "resources", roster.getResources(tojid)
client.disconnect()
def message_cb(session, message):
print ">", message
sendMessage(USERNAME + '/Talk', "This is an automatically generated gtalk message: did you get it?")
I have a very simple piece of code that I used in previous versions of Python without issues (version 2.5 and prior). Now with 3.0, the following code give the error on the login line "argument 1 must be string or buffer, not str".
import smtplib
smtpserver = 'mail.somedomain.com'
AUTHREQUIRED = 1 # if you need to use SMTP AUTH set to 1
smtpuser = 'admin#somedomain.com' # for SMTP AUTH, set SMTP username here
smtppass = 'somepassword' # for SMTP AUTH, set SMTP password here
msg = "Some message to send"
RECIPIENTS = ['admin#somedomain.com']
SENDER = 'someone#someotherdomain.net'
session = smtplib.SMTP(smtpserver)
if AUTHREQUIRED:
session.login(smtpuser, smtppass)
smtpresult = session.sendmail(SENDER, RECIPIENTS, msg)
Google shows there are some issues with that error not being clear, but I still can't figure out what I need to try to make it work. Suggestions included defining the username as b"username", but that doesn't seem to work either.
UPDATE: just noticed from a look at the bug tracker there's a suggested fix also:
Edit smtplib.py and replace the existing encode_plain() definition with this:
def encode_plain(user, password):
s = "\0%s\0%s" % (user, password)
return encode_base64(s.encode('ascii'), eol='')
Tested here on my installation and it works properly.
Traceback (most recent call last):
File "smtptest.py", line 18, in <module>
session.login(smtpuser, smtppass)
File "c:\Python30\lib\smtplib.py", line 580, in login
AUTH_PLAIN + " " + encode_plain(user, password))
File "c:\Python30\lib\smtplib.py", line 545, in encode_plain
return encode_base64("\0%s\0%s" % (user, password))
File "c:\Python30\lib\email\base64mime.py", line 96, in body_encode
enc = b2a_base64(s[i:i + max_unencoded]).decode("ascii")
TypeError: b2a_base64() argument 1 must be bytes or buffer, not str
Your code is correct. This is a bug in smtplib or in the base64mime.py.
You can track the issue here:
http://bugs.python.org/issue5259
Hopefully the devs will post a patch soon.
As a variation on Jay's answer, rather than edit smtplib.py you could "monkey patch" it at run time.
Put this somewhere in your code:
def encode_plain(user, password):
s = "\0%s\0%s" % (user, password)
return encode_base64(s.encode('ascii'), eol='')
import smtplib
encode_plain.func_globals = vars(smtplib)
smtplib.encode_plain = encode_plain
This is kind of ugly but useful if you want to deploy your code onto other systems without making changes to their python libraries.
This issue has been addressed in Python3.1. Get the update at http://www.python.org/download/releases/3.1/