I am new to Python and, in fact, I have limited programming experience in general.

I am attempting to create a web form that our HR employees can use to add new employees into Active Directory and to create a mailbox for that user. AD is on a WIN2k server and Exchange 2000. I have the form and some code that will add the user based on submitted fields from the webform. The code fails when it gets to the part about creating the mailbox. Below is my code:

import win32com.client
import win32com, win32com.adsi
import pythoncom
import cgi

FormFile = "addusertmp.html"
print 'Content-Type: text/html\n\n'
def DisplayForm():
    FormHandle = open(FormFile, "r")
    FormInput = FormHandle.read()
    FormHandle.close()
    print FormInput

def ProcessForm(entries):
    first = entries['first'].value
    last = entries['last'].value
    login = entries['login'].value
    password = entries['password'].value
    title = entries['title'].value

entries = cgi.FieldStorage()

def add_acct (location, user):
    ad_obj=win32com.client.GetObject(location)

    ad_user=ad_obj.Create('user','cn='+user['login'])
    ad_user.Put('sAMAccountName',user['login'])
    ad_user.Put('userPrincipalName',user['login']+'@domain.org')
    ad_user.Put('DisplayName',user['first']+' '+user['last'])
    ad_user.Put('givenName',user['first'])
    ad_user.Put('sn',user['last'])
    ad_user.Put('description',user['title'])
    ad_user.SetInfo();ad_user.GetInfo()
    ad_user.AccountDisabled=0
    ad_user.setpassword(user['password'])
    ad_user.SetInfo()
    ad_user.CreateMailbox('CN=Maibox Store (SERVER),CN=First Storage Group,CN=InformationStore,CN=SERVER,CN=Servers,CN=First Administrative Group,CN=Administrative Groups,CN=Company Name,CN=Microsoft Exchange,CN=Services,CN=Configuration'+location)
    ad_user.EmailAddress=user+'@domain.org'
    ad_user.SetInfo()
    ad_user.Put('msExchUserAccountControl',2)
    ad_user.SetInfo()

if entries:
    location='LDAP://OU=Employees,DC=domain,DC=org'
    user={'first':entries.getvalue('first'),'last':entries.getvalue('last'),'login':entries.getvalue('login'),'title':entries.getvalue('title'),'password':entries.getvalue('password')}
    print user
    add_acct(location,user)
    print "user added"
else:
    DisplayForm()

When I go to the web form and I enter&submit the required fields, this creates the user & enables the user, but also produces the following error and never creates the mailbox:
{'password': 'test', 'login': 'bbonez', 'title': 'Bouncer', 'last': 'Bonez', 'first': 'Big'} Traceback (most recent call last): File "W:\SysadminSite\adduser2.cgp", line 50, in ? add_acct(location,user) File "W:\SysadminSite\adduser2.cgp", line 37, in add_acct ad_user.CreateMailbox('CN=Maibox Store (SERVER),CN=First Storage Group,CN=InformationStore,CN=SERVER,CN=Servers,CN=First Administrative Group,CN=Administrative Groups,CN=Company Name,CN=Microsoft Exchange,CN=Services,CN=Configuration'+location) File "C:\Python22\Lib\site-packages\win32com\client\", line 438, in __getattr__ raise AttributeError, "%s.%s" % (self._username_, attr) AttributeError: .CreateMailbox

Any help would be GREATLY appreciated. Thank you!

Dani AI

Generated

the traceback is happening because CreateMailbox is not an ADSI user method. It lives on the CDOEXM interface IMailboxStore, so you must call it on that interface for the user object. Also, MailEnable is for mail-enabled (no mailbox) recipients, not mailbox-enabled users, so drop that call. Finally, the mailbox store DN must be in the Configuration naming context; do not append your user OU to it. Example shape: LDAP://CN=Mailbox Store (SERVER),... ,CN=Configuration,DC=domain,DC=org. (learn.microsoft.com)

One reliable pattern is: create/commit the user with ADSI, then bind to the same user via CDO.Person and ask for the IMailboxStore interface to create the mailbox. Minimal Python (pywin32 + CDOEXM) sketch:

from win32com.client.gencache import EnsureDispatch

user_dn = "CN={login},OU=Employees,DC=domain,DC=org"
home_mdb = ("LDAP://CN=Mailbox Store (SERVER),CN=First Storage Group,"
            "CN=InformationStore,CN=SERVER,CN=Servers,CN=First Administrative Group,"
            "CN=Administrative Groups,CN=Company Name,CN=Microsoft Exchange,"
            "CN=Services,CN=Configuration,DC=domain,DC=org")

p = EnsureDispatch("CDO.Person")
p.DataSource.Open(f"LDAP://{user_dn}")
mbx = p.GetInterface("IMailboxStore")
mbx.CreateMailbox(home_mdb)
p.DataSource.Save()

If you need early-bound wrappers, run the COM Makepy utility for the CDOEXM type library before running your script. (learn.microsoft.com)

Post-provisioning tips that address the rest of your code/questions and ’s note: set mailNickname (alias) on the user before mailboxing; do not set EmailAddress (the AD attribute is mail, and Exchange will stamp mail and proxyAddresses for you). The mailbox’s physical store is created on first delivery or first logon; new addresses/GAL visibility appear after the Recipient Update Service stamps the object. Also, avoid forcing msExchUserAccountControl; RUS should stamp it (value 0 for mailbox-enabled). If you set it to 2, Exchange can treat the mailbox as disabled. Trigger RUS Update Now if you are testing and want immediate stamping. (itprotoday.com)

Hope that unblocks you, and +1 to ’s suggestion to validate user creation first before mailboxing.

Recommended Answers

All 4 Replies

It looks like your problem is on the Windows end rather than the Python end. Apparently, a 'user' object's CreateMailbox() method requires something different from what you are supplying. As a result, Server 2k is choking but (as usual) isn't telling you exactly why.

If the error were Python-related, you would get a much more descriptive message :).

We did something like what you are trying to do at school, but handled it by having Python create a .csv file for all users and then used Active Directory to import the users from the .csv file. I can't recall the details at the moment, but it seems unlikely to be appropriate to your situation.

I would recommend the following:

* Try commenting out the code that concerns mailbox creation (lines 37-41, if I'm reading it right).
* Make sure that you can use the web form to create a new user. Make sure the new user goes into the right OU and is a member of all of the right security groups!
* Check your Server 2k documentation for the right syntax for the CreateMailbox. See if you can debug lines 37-41 that way.

Hope it helps,
Jeff

Thanks for the insight. The code does, in fact, create the user in the proper groups. It creates it with the correct password and the account is enabled.

So it makes sense what you're saying about Server 2k rejecting the "CreateMailbox" syntax. I will see if I can research what I need to be using to get that mailbox created. If anybody can help me out here, I would appreciate it.

Alright, so I have gotten a bit further, but could use a bit more help. My code now looks like:

import win32com.client
import win32com, win32com.adsi
import cdoexm
import pythoncom
import cgi

FormFile = "addusertmp.html"
print 'Content-Type: text/html\n\n'
def DisplayForm():
    FormHandle = open(FormFile, "r")
    FormInput = FormHandle.read()
    FormHandle.close()
    print FormInput

def ProcessForm(entries):
    first = entries['first'].value
    last = entries['last'].value
    login = entries['login'].value
    password = entries['password'].value
    title = entries['title'].value

entries = cgi.FieldStorage()

def add_acct (location, user):
    ad_obj=win32com.client.GetObject(location)

    ad_user=ad_obj.Create('user','cn='+user['login'])
    ad_user.Put('sAMAccountName',user['login'])
    ad_user.Put('userPrincipalName',user['login']+'@garcoschools.org')
    ad_user.Put('DisplayName',user['first']+' '+user['last'])
    ad_user.Put('givenName',user['first'])
    ad_user.Put('sn',user['last'])
    ad_user.Put('description',user['title'])
    ad_user.SetInfo();ad_user.GetInfo()
    ad_user.AccountDisabled=0
    ad_user.setpassword(user['password'])
    ad_user.SetInfo()
    ad_user.MailEnable("SMTP:"+user['login']+"@domain.org")
    ad_user.SetInfo()
    HomeMDB=('CN=Mailbox Store (SERVER),CN=First Storage Group,CN=InformationStore,CN=SERVER,CN=Servers,CN=First Administrative Group,CN=Administrative Groups,CN=Company name,CN=Microsoft Exchange,CN=Services,CN=Configuration,OU=Employees,DC=domain,DC=org')
    cdoexm.IMailboxStore.CreateMailbox(HomeMDB)
    ad_user.EmailAddress=user['login']+'@domain.org'
    ad_user.SetInfo()
    ad_user.Put('msExchUserAccountControl',2)
    ad_user.SetInfo()


entries=1  #test line, remove later
if entries:
    location='LDAP://OU=Employees,DC=domain,DC=org'
#    user={'first':entries.getvalue('first'),'last':entries.getvalue('last'),'login':entries.getvalue('login'),'title':entries.getvalue('title'),'password':entries.getvalue('password')}
    user={'first':'jason','last':'bourne','login':'bbourne2','title':'Assassin','password':'password'}  #testline, remove later
    print user
    add_acct(location,user)
    print "user added"
else:
    DisplayForm()

The error I get now is:
File "E:\Projects\Python\SysAdmin\tests\", line 41, in add_acct
cdoexm.IMailboxStore.CreateMailbox(HomeMDB)
TypeError: unbound method CreateMailbox() must be called with IMailboxStore instance as first argument (got str instance instead)

Any idea what I'm doing wrong? Thanks

Hi,

The error I get now is:
File "E:\Projects\Python\SysAdmin\tests\", line 41, in add_acct
cdoexm.IMailboxStore.CreateMailbox(HomeMDB)
TypeError: unbound method CreateMailbox() must be called with IMailboxStore instance as first argument (got str instance instead)

this is what it comes to me at the moment, CreateMailBox() method of IMailboxStore class.

So when you are calling a member function class, you can call member function in two ways..
- using instance of the class and function parameters
- using class name, and passing the instance of the class as first argument and function parameters following it, to the function.

In your case you are passing an argument of string type as first argument, hence you get TyoeError exception. So you need to pass, an instance of IMailboxStore class as first argument.

Below is the sample code, which is similar to your's.. helps you in better understanding the problem

>>> class test:
	def fun(self):
		print 'hi'

		
>>> t=test() # creating an instance
>>> t.fun()	# calling function using instance of the class itself
hi
>>> test.fun()

Traceback (most recent call last):
  File "<pyshell#11>", line 1, in -toplevel-
    test.fun()
TypeError: unbound method fun() must be called with test instance as first argument (got nothing instead)
>>> test.fun(t)	# calling member function with the instance of the class
hi
>>>

Hope i explained the problem properly, all the best.

kath.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.