Tuesday, July 10, 2007

Setting the Homepage on a Outlook Folder via a script

I’ve had a number of people ask this question in the past so I thought I’d post up a script to help out those they may want to look at doing this.

When you set the Outlook homepage within Outlook it configures the PR_FOLDER_WEBVIEWINFO or http://schemas.microsoft.com/mapi/proptag/0x36DF0102 property. This property is a Binary property who’s format is undocumented but using a Mapi editor like OutlookSpy or MfcMapi you can work out the format that this follows. The basic format is

dwVersion: 0x00000002
dwType: 0x00000001
dwFlags: 0x00000001
dwUnused: 0x0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
cbData: 0x188 (000000BC)
bData: http://yoururl.com

If you want to set this property in a script the 3 values you need to worry about are

dwFlags If this is set to 1 then the check box in Outlook for “Show homepage by default for this folder” will be checked.

cbData is the number of bytes (8 bits or 2 hex digits) or the url in Bdata + the spacers

bData is the URL of the webpage you want to point to encoded in Hex.

The following script handles encoding URL’s that are up to 255 characters long if you want to have URL’s that are longer than 255 charterers then you need to change the code for cbData. The rest of the code builds the binary property. The AsciiToHex to function encodes the Ascii string 1 byte for each letter hence the extra padding needed.

The one thing to note is this is a unsupported thing to do so make sure you do plenty of your own testing first.

I’ve created 2 versions of the script one version uses codex and the other cdo1.2 they do basically the same thing. They first check for an instance of a folder in a mailbox (the cdo1.2 version only checks the Root folder). If an instance of that folder is found then its sets the homepage property on the folder else it creates the folder and sets the homepage. In this sample the folder is called webfolder and it sets the homepage of that folder to a search about coffee tasting in Sydney.

I’ve put a downloadable copy of the script here the code itself looks like.

homepage = "http://yoururl.com"
dwVersion = "02"
dwType = "00000001"
dwFlags = "00000001"
dwUnused = "00000000000000000000000000000000000000000000000000000000"
bData = AsciiToHex(homepage)
cbDataSize = cstr(ubound(bData)+1)
propval = dwVersion & dwType & dwFlags & dwUnused & "000000" & Hex(cbDataSize) & "000000" & Join(bData,"")

set rec = createobject("ADODB.Record")
rec.open "file://./backofficestorage/domain.com/MBX/mailbox/webfolder/", ,3,33562624
rec.fields("http://schemas.microsoft.com/mapi/proptag/0x36DF0102").value = propval
rec.fields.update
rec.close


Function AsciiToHex(sData)
Dim i, aTmp()
ReDim aTmp((Len(sData)*2) + 1)
arnum = 0
For i = 1 To Len(sData)
aTmp(arnum) = Hex(Asc(Mid(sData, i)))
arnum = arnum + 1
aTmp(arnum) = "00"
arnum = arnum + 1
Next
aTmp(arnum) = "00"
arnum = arnum + 1
aTmp(arnum) = "00"
ASCIItoHex = aTmp
End Function

25 comments:

Anonymous said...

Hi Glen,

I read with interest your recent article on setting the homepage of an outlook folder via a MAPI property (http://gsexdev.blogspot.com/2007/07/setting-homepage-on-outlook-folder-via.html). I am trying to do a similar thing but using WebDAV instead of MAPI and I was wondering if maybe you could help me work out why my code does not work.

I have created a folder in my outlook and set the homepage of it to be the BBC news website. If I look at this folder in OutlookSpy, I can see that its PR_FOLDER_WEBVIEWINFO property is set to the following value:

020000000100000001000000000000000000000000000000000000000000000000000000000000002C00000068007400740070003A002F002F006E006500770073002E006200620063002E0063006F002E0075006B000000

OutlookSpy translates this as:

dwVersion: 0x00000002
dwType: 0x00000001
dwFlags: 0x00000001
dwUnused: 0x0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
cbData: 0x44 (0000002C)
bData: http://news.bbc.co.uk


I have a second folder in my mailbox that I want to set the homepage on. I figure that I should be able to make a WebDAV request to set it like any other property. I construct and send a request like this:

========= Outbound Message =========
PROPPATCH ***my mailbox URI here***/homepageTest/ HTTP/1.1
Host: ***my exchange server here***
Connection: TE
TE: trailers, deflate, gzip, compress
User-Agent: UCI DAV Explorer/0.91 RPT-HTTPClient/0.3-3E
Translate: f
Authorization: Basic a21jY29ybWFja0BuYXlhdGVrLmNvbTpNYXJxdWVzMQ==
Accept-Encoding: deflate, gzip, x-gzip, compress, x-compress
Content-type: text/xml
Content-length: 377

<?xml version="1.0"?>
<A:propertyupdate xmlns:A="DAV:" xmlns:B="http://schemas.microsoft.com/mapi/proptag/">
<A:set>
<A:prop>
<B:x36DF0102>020000000100000001000000000000000000000000000000000000000000000000000000000000002C00000068007400740070003A002F002F006E006500770073002E006200620063002E0063006F002E0075006B000000</B:x36DF0102>
</A:prop>
</A:set>
</A:propertyupdate>

========= Inbound Message =========
HTTP/1.1 207 Multi-Status
Date: Sun, 05 Aug 2007 20:40:40 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
MS-Exchange-Permanent-URL: ***my mailbox URI here***/-FlatUrlSpace-/6539cf6ac3d3f84dbb289d46b1dd6cb6-124a951
Repl-UID: <rid:6539cf6ac3d3f84dbb289d46b1dd6cb6000000a36508>
Content-Type: text/xml
Content-Length: 321
ResourceTag: <rt:6539cf6ac3d3f84dbb289d46b1dd6cb6000000a365086539cf6ac3d3f84dbb289d46b1dd6cb60000012511ec>
MS-WebStorage: 6.5.7638
MS-WebStorage: 6.5.7638
X-Powered-By: ASP.NET

<?xml version="1.0"?><a:multistatus xmlns:b="http://schemas.microsoft.com/mapi/proptag/" xmlns:a="DAV:"><a:response><a:href>***my mailbox URI here***/homepageTest</a:href><a:propstat><a:status>HTTP/1.1 200 OK</a:status><a:prop><b:x36DF0102/></a:prop></a:propstat></a:response></a:multistatus>

You can see that the exchange server acknowledges that the request has succeeded. However, when I look in OutlookSpy, the value of the PR_FOLDER_WEBVIEWINFO attribute is nothing like what I set it as. It is set to:

D36D34D34D34D35D34D34D34D35D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D34D82D34D34D34EBCD34EF8D34EF8D34EF4D34DC0D34D85D34D85D34E84D34EB9D34EFBD34EF7D34D84D34EB6D34EB6D34EB7D34D84D34EB7D34E85D34D84D34EF9D34E81D34D34D34

which OutlookSpy breaks down as:

dwVersion: 0xD3346DD3
dwType: 0x5DD3344D
dwFlags: 0x344DD334
dwUnused: 0x0xD3345DD3, 0x4DD3344D, 0x344DD334, 0xD3344DD3, 0x4DD3344D, 0x344DD334, 0xD3344DD3
cbData: 0x1305687117 (4DD3344D)
bData: ??????????????????????????????????????????????????


I am at a loss to explain why this property is not updated properly. The only thing I can think of is that it is some kind of encoding issue. Perhaps the Exchange server is not correctly understanding the HEX that I am passing it. Do you have any idea of the encoding that Exchange is expecting here?

I do not have a huge amount of experience working with Exchange. Is there perhaps a log file that I could examine that might give a clue as to what is going wrong?

Thanks for any help that you might be able to offer in this matter.

If you would like to contact me directly, please reply to the email I sent to your Yahoo account.

Glen said...

You need to Base64 encoded you proppatch value you also need to make sure you specify the datatype and also include that in your header for bbc new site you proppatch would look like

<?xml version="1.0" encoding="utf-8"?><d:propertyupdate xmlns:d="DAV:"
xmlns:m="http://schemas.microsoft.com/mapi/proptag/" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">

<d:set>
<d:prop>
<m:0x36DF0102 b:dt="bin.base64">AgAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAABoAHQAdABwADoALwAvAG4AZQB3AHMALgBiAGIAYwAuAGMAbwAuAHUAawAAAA==

</m:0x36DF0102>
</d:prop>
</d:set>
</d:propertyupdate>

Anonymous said...

Hi Glen,

Thank you so much for your prompt respone and help with this - it is now working great. In case this information helps anyone else out there, my WebDAV request looks slightly different to yours:

PROPPATCH *** my URI here***/homepageTest/ HTTP/1.1
Host: *** my server here ***
Connection: TE
TE: trailers, deflate, gzip, compress
User-Agent: UCI DAV Explorer/0.91 RPT-HTTPClient/0.3-3E
Translate: f
Authorization: Basic a21jY29ybWFja0BuYXlhdGVrLmNvbTpNYXJxdWVzMQ==
Accept-Encoding: deflate, gzip, x-gzip, compress, x-compress
Content-type: text/xml
Content-length: 333

<?xml version="1.0"?>
<A:propertyupdate xmlns:A="DAV:" xmlns:B="http://schemas.microsoft.com/mapi/proptag/">
<A:set>
<A:prop>
<B:x36DF0102>AgAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADYAAABoAHQAdABwADoALwAvAHcAdwB3AC4AZwB1AGEAcgBkAGkAYQBuAC4AYwBvAC4AdQBrAC8AAAA=</B:x36DF0102>
</A:prop>
</A:set>
</A:propertyupdate>

I did not actually have to specify the encoding in the end.


To anyone else doing this in Java, here is some code to generate the appropriate base-64 encoded value for a website URL. It makes use of the Apache commons codec library so you will have to download that and add it to your classpath to get this to work.


import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;


public class HomepageDemo {

public static void main(String[] args) throws Exception {
HomepageDemo demo = new HomepageDemo();
demo.buildFolderHomepageBase64String("http://news.bbc.co.uk");
}


/**
* build the base-64 encoded value for the binary folder homepage property.
*
* @param homepage
* @return
* @throws Exception
*/
private String buildFolderHomepageBase64String(String homepage) throws Exception {

String hexValue = buildFolderHomepageHexString(homepage);
byte[] hexBytes = Hex.decodeHex(hexValue.toCharArray());
byte[] base64EncodedBytes = Base64.encodeBase64(hexBytes);
String result = new String(base64EncodedBytes);

System.out.println("Folder homepage property (base64) : " + result);

return result;
}


/**
* Build the binary value used to update the PR_FOLDER_WEBVIEWINFO MAPI
* property that expresses the homepage of an Outlook folder.
*
*/
private String buildFolderHomepageHexString(String homepage) throws Exception {

String homepageBytes = buildFolderHomepageBData(homepage);
String dwVersion = "02";
String dwType = "00000001";
String dwFlags = "00000001";
String dwUnused = "00000000000000000000000000000000000000000000000000000000";

String cbDataSize = Integer.toHexString((homepage.length() + 1) * 2);

String propval = dwVersion + dwType + dwFlags + dwUnused + "000000"
+ cbDataSize + "000000" + homepageBytes;

System.out.println("Folder homepage property (hex) : " + propval);

return propval;
}

/**
*
* build the bData attribute of the folder homepage hex string. This
* basically requires that the homepage value is encoded in a certain way.
*
* @param homepage
* @return
*/
private String buildFolderHomepageBData(String homepage) {
char[] result = new char[homepage.length() * 4 + 4];
byte[] homepageBytes = homepage.getBytes();
int index = 0;
for (int i = 0; i < homepageBytes.length; i++) {
byte b = homepageBytes[i];
char[] chars = Hex.encodeHex(new byte[] {b});
result[index++] = chars[0];
result[index++] = chars[1];
result[index++] = '0';
result[index++] = '0';
}
result[index++] = '0';
result[index++] = '0';
result[index++] = '0';
result[index++] = '0';

System.out.println("Folder homepage bData value : " + new String(result));

return new String(result);
}

}

Anonymous said...

Anyone know how to do the same thing through OWA?

Glen said...

If you want to do this via WebDAV see the comment above someone has provided the code to do this. OWA will never show the homepage for a folder it just doesn't have this functionality.

Cheers
Glen

kwiatkowski said...

Hello,

I have downloaded and used your script to create folder with homepage in my Outlook 2007 connected to Exchange 2007.

Everything was working fine up to the point I tried to update/change homepage address in the folder previously created.

I am receiving following Error message:

sethomepagecdo12.vbs(36, 2) Collaboration Data Objects:
[Collaboration Data Objects - [MAPI_E_COLLISION(80040604)]]

I tried to modify the script to not create the folder again but the homepage is not being updated at all.

Please advice.

Thanks,

Kris

Glen said...

Have a look at the this part of the script

Do While (Not bFound) And Not (CdoFolder Is Nothing)
If LCase(CdoFolder.Name) = "webfolder" Then
bFound = True
Else
Set CdoFolder = CdoFolders.GetNext
End If
Loop

This is where its searching through the mailbox to find the folder. Did you update the webfolder to name of the folder you used. If this isn't finding the folder then the modification section wont work. You might want to try putting in some wscript.echo so you can track the status.

cheers
Glen

Glen said...

Kris,

Okay i can see the issue now i was able to reproduce it using the same foldername. Its because there is a LCASE in the following line

If LCase(CdoFolder.Name) = "Mail Archive Folder" Then

so its converting the name to lowercase and then failing the match because its case sensitive. One quick fix is to remove the lcase or do something like

If LCase(CdoFolder.Name) = lcase("Mail Archive Folder") Then

I've update the download for the post to fix this issue and make it a little cleaner (eg one variable for the foldername) I tested with yours setting and it seems to work okay. The change you made to the if statement should be necessary.

cheers
Glen

kwiatkowski said...

This is now working perfectly fine – thank you so much for your help.

Regards,
Kris

Tony said...

Hi
I ran the cdo12.vbs and i am getting the following error. pls advice.


Line: 16
Char: 1
Error: ActiveX component can't create object: 'MAPI.Session'
Code: 800A01AD
Source: Microsoft VBScript runtime error

---------------------------
OK
---------------------------

Anonymous said...

Please make sure you have installed CDO/MAPI 1.2.1 on the computer you are trying to run the script.

Kris

Anonymous said...

how about mapi 6.5?

kwiatkowski said...

As long as CDO.DLL is properly registered - should not make a difference.

Kris

Anonymous said...

Hi Glen,

Is it possible to do this with public folders also? I'm looking to scan the public folder tree put a homepage on each one.

Thanks,
Mike

Glen said...

Yep it should be the same property on a public folder to access the public Folder tree in CDO just use something like

Set objpubstore = objSession.InfoStores("Public Folders")

The interate through the folders collection to find the folder your after. (Unless you know the EntryID)

Cheers
Glen

Anonymous said...

Hi Glen,

I too am trying to set the home page on a public folder.

I modified your script as follows but haven't run it yet, as I fear I'm missing something.

I'm using mfcmapi to look at the properties of the PF I created.

homepage = "https://portal.cttgroup.com"
dwVersion = "02"
dwType = "00000001"
dwFlags = "00000001"
dwUnused = "00000000000000000000000000000000000000000000000000000000"
bData = AsciiToHex(homepage)
cbDataSize = cstr(ubound(bData)+1)
propval = dwVersion & dwType & dwFlags & dwUnused & "000000" & Hex(cbDataSize) & "000000" & Join(bData,"")

Set objpubstore = objSession.InfoStores("Public Folders")
rec.open "file://./backofficestorage/cttgroup.local/MBX/mailbox/Portal/", ,3,33562624
rec.fields("http://schemas.microsoft.com/mapi/proptag/0x36DF0102").value = propval
rec.fields.update
rec.close


Function AsciiToHex(sData)
Dim i, aTmp()
ReDim aTmp((Len(sData)*2) + 1)
arnum = 0
For i = 1 To Len(sData)
aTmp(arnum) = Hex(Asc(Mid(sData, i)))
arnum = arnum + 1
aTmp(arnum) = "00"
arnum = arnum + 1
Next
aTmp(arnum) = "00"
arnum = arnum + 1
aTmp(arnum) = "00"
ASCIItoHex = aTmp
End Function

is the backoffice URL correct? (I don't think so but am a little lost here).

Glen said...

Where do you want to run the script if you use CDOEX then you will need to run this locally on the Exchange Server where there is a instance of the public folder or where you want to create an instance of the public folder. If you are going to use CDOEX then you dont need

Set objpubstore = objSession.InfoStores("Public Folders")

This is only needed in CDO 1.2

Your path isn't correct you should use the default SMTP domain from your default recipient policy and the path to the public folder have a look at http://msdn.microsoft.com/en-us/library/aa123685(EXCHG.65).aspx which explains how to form a proper url.

If you want to run the script remotly then you need to look at using the CDO 1.2 version instead

Cheers
Glen

Jim said...

Doesn't appear that either of these work with Exchange 2007. Anyone have any insight or a way to do this?

Jim said...

Let me clarify my previous posting, we're trying to create a couple of home page linked folders in all user mailboxes on Exchange 2007 using Outlook 2003 clients. Everything I read is that CDO 1.2.1 and MAPI 6.5 are not compatible with Outlook 2003 or earlier. Any workaround to make this work?

Glen said...

This works fine against any Exchange server just dont run it on the server itself as mapi ins't install just run it from a workstation. A better method on 2007 is to use EWS see http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/thread/8d50f961-25fa-4bab-95d1-c92dfcd66044/

Cheers
Glen

Anonymous said...

Hi Glen,

When i execute WebDAV method "Propatch" then it works fine on one exchange 2k3 server, but it doesn't work on another exchange 2k3 server. I get "500" server error. Could you please help me?

Thanks,
Vishal

Glen said...

Make sure you have a translate f header or test webdav is working with pfdavadmin.

Cheers
Glen

Anonymous said...

Can I put an https URL as the homepage? I am not able to display the page in that case, any idea???

Glen said...

No Https isn't supported by Outlook as far as i know.

Cheers
Glen

Anonymous said...

Glen thanks.

Again, you saved my time !

You're the Boss !