Monday, January 19, 2009

Sending emails with Collaboration Data Objects (CDO) and Dexterity


One of the things I always tell other Microsoft Dynamics GP developers is not to discard the power of Dexterity. Not because there is .NET and Visual Studio Tools it means that you should abandon Dexterity as a development option (while I confess, I am in the process of increasing my knowledge of C# and so on).

Business Situation

A common request is the ability to submit emails from within your Dexterity-based application. However, emails are not always straight forward. In environments where Dynamics GP resides on a Citrix farm or Terminal Server, companies are reluctant to install Microsoft Office and/or setup email profiles for everyone. After all, that's what the Exchange Server is for. So, how can you get email messages sent from your application without SMTP, Exchange, or Outlook?

Background

Collaboration Data Objects (CDO) has been around for quite sometime and is Microsoft's technology for building messaging or collaboration applications or adding these capabilities to existing applications, including Dexterity applications.

CDO is the basis of Microsoft Exchange, and has evolved from OLE Messaging and Active Messaging. Using Microsoft Dexterity with CDO, a developer can, for example, write a script that will exchange e-mail with users or with other Dexterity applications, collaborate in discussions on other applications, or allow employees to schedule meetings with multiple recipients, review existing appointments, schedule new events, and so forth.

Collaborative Data Objects are made available through two CDO libraries. These libraries let you address programmable messaging objects (including folders, messages, recipient addresses, attachments, and other messaging components).

Solution

To implement CDO in Dexterity, the following steps are required:

1) Open Resource Explorer. Click on Base and highlight the Library entry. Click on the New button to continue. This will open the COM Type Library Definition window.

2) Click on the ellipses button and locate and add the Microsoft CDO for Windows 2000 Library in the COM Type Libraries.












* Click on image to enlarge

3) Click on the Select button to continue, click on the OK button to close the COM Type Library Definition window.

4) Now, you will need to create a Data Type that will reference the library. In Resource Explorer, locate the Data Type folder under Base resources. Click on the New button in the Dexterity toolbar. I set up the following information for this example:














NOTE: To select the COM Object Type click on the ellipses button. This will open the Class Browser window. Double-click on the Message class. In reality, Dexterity is able to access other classes for that object without the need for other references, which simplifies things as we will see ahead.
















5) With our new data type in place, we can now create a global script that will allow us to send emails from within GP using our CDO object.

Send_Email

{ global script : Send_Email

(C) 2009, created by Mariano Gomez, MVP
This script uses a non-SMTP method of sending emails to receipients
}

in string IN_From_Recipient;
in string IN_To_Recipient;
in string IN_Subject;
in text IN_Body;

local CDO.Message objEmail;
local reference configParams;

local string cdoSendUsingMethod;
local string cdoSMTPServer;
local string cdoSMTPServerPort;
local string smtpServer;

pragma (disable warning LiteralStringUsed);

cdoSendUsingMethod = "http://schemas.microsoft.com/cdo/configuration/sendusing";
cdoSMTPServer = "http://schemas.microsoft.com/cdo/configuration/smtpserver";
cdoSMTPServerPort = "http://schemas.microsoft.com/cdo/configuration/smtpserverport";
smtpServer = "mail.somesmptrelay.com"; {* this is the address of the smtp relay server }

pragma (enable warning LiteralStringUsed);

configParams = new CDO.Configuration();

{ Configure parameters }
configParams.Fields.Item[cdoSendUsingMethod].Value = CDO.cdoSendUsingPort;
configParams.Fields.Item[cdoSMTPServer].Value = smtpServer;
configParams.Fields.Item[cdoSMTPServerPort].Value = 25;
configParams.Fields.Update();

{ Prepare and send the email }

objEmail = new CDO.Message();

{ set up recipient and sender infomation }
objEmail.Configuration = configParams;
objEmail.From = IN_From_Recipient;
objEmail.To = IN_To_Recipient;
objEmail.Subject = IN_Subject;
objEmail.Textbody = IN_Body;
objEmail.Send();

clear objEmail;
clear configParams;
A few things to highlight in the code:

a) Dexterity will not allow you to access the configuration parameters in the Message object directly, as you would in VB or VBA. This is, you will not be able to invoke objEmail.Configuration.Fields.Item directly. Hence, there will be a need to create a separate reference to the Configuration object.

b) While in VB you are able to use the parenthesis () as a way to access the different elements of the Configuration class, in Dexterity is necessary to use the square brackets along with a variable representing the element to be initialized. Also, it is necessary to specify the keyword ".Value" in the scope to avoid a Dexterity crash. VB does not require the specification of the ".Value" in the scope.


{ Configure parameters }
configParams.Fields.Item[cdoSendUsingMethod].Value = CDO.cdoSendUsingPort;
configParams.Fields.Item[cdoSMTPServer].Value = smtpServer;
configParams.Fields.Item[cdoSMTPServerPort].Value = 25;
Also, to access class constants, it will be necessary to add "CDO." in front of the constant name. I suspect this to be the issue with other objects as well.

c) To pass in the Configuration values to our Message class, it is enough to initialize objEmail.Configuration with the configuration parameter (configParams) reference.

While working with COM objects may not come intuitively in Dexterity -- we also don't have intellisense capabilities -- it's very true that you can still accomplish a great deal of the techniques that are natural in other environments like VB. After all COM is COM.

OTHER RESOURCES:

KB 286431 - How to send HTML formatted mail using CDO for Windows 2000 and a remote SMTP service.

Hey 1129 - Hey, Scripting Guy! - How Can I Attach a File to an Email Sent Using CDO?

MSDN 978698 - Collaboration Data Objects Roadmap

Until next post!

MG.-
Mariano Gomez, MVP
Maximum Global Business, LLC
http://www.maximumglobalbusiness.com/

7 comments:

Ravi Polepalli said...

Hi
Its working fine for me, but the problem is i am not able to send mails to external users its giving me the following problem, can you please advise how to resolve it

Unhandled object exception:
The server rejected one or more recipient addresses. The server response was: 554 5.7.1 external mail address; Relay access denied

Mariano Gomez said...

This is usually an issue with your ISP. Most ISPs will not allow you to relay emails through their servers without authentication. Here are a few things:

*This is happening because your objMsg.SmtpServer is rejecting addresses.

* Make sure all email addresses specified at objMsg.To, objMsg.Cc, objMsg.Bcc and objMsg.From are valid email addresses.

* Make sure you have permissions to relay through the server.
Make sure the objMsg.From has permissions to relay through the server.

Best regards,

MG.-
Mariano Gomez, MVP

Amin A Rahim said...

Hello,

I need little bit help.

I want to pass User ID and Password to login to my SMTP Server.

Please help.

Thanks.

Mariano Gomez said...

Amin,

Add the following code:


local string cdoSendUserName;
local string cdoSendPassword;
.
.
cdoSendUserName = "http://schemas.microsoft.com/cdo/configuration/sendusername";
cdoSendPassword = "http://schemas.microsoft.com/cdo/configuration/sendpassword";
.
.
configParams.Fields.Item[cdoSendUserName].Value = someUserName;
configParams.Fields.Item[cdoSendPassword].Value = somePassword;

You can pass the user name and password as in parameters to your email function.

Best regards,

MG.-
Mariano Gomez, MVP

Mary Lynn said...

Hi,

Along with sending email, is there a way to access and read existing Outlook email content using Dexterity/CDO?

Seth said...

I was wondering the same thing as Mary above. Is it possible to access my Outlook contact list in Dexterity? If so, do you have an example? Thanks.

Mariano Gomez said...

Seth,

It is possible to access your Outlook contact list from Dex. Read up on the MAPI functions in your Dex help file.

MG.-