Using the Messaging Server Plug-in API
Table of Contents | Previous | Next | Index

Messaging Server Plug-in API Guide


Chapter 2
Using the Messaging Server Plug-in API

This chapter describes using the Messaging Server Plug-in API to write server plug-ins.

The chapter has the following sections:

[Top]

Writing the Initialization and Plug-in Functions

Every Messaging Server plug-in must export two plug-in function prototypes in order to load. This section describes the initialization and plug-in functions.

[Top]

Writing an Initialization Function

Your plug-in must export an initialization function based on the pInitFunc function prototype. Called once at MTA startup, the function initializes local server data, loads configuration information off the disk, declares global variables, and returns an integer that indicates whether the initialization succeeded. The plug-in function is relieved of this task, so a boost to performance results.

typedef int (*pInitFunc)(pblock *Config);
The Config parameter represents configuration data that is relevant to plug-in operation. It points to the name:value pairs that contain all the optional parameters on the configuration command line. For example, the no-xlate-domains parameter in the example in "How Messaging Server Plug-ins Work" is passed in the parameter block Config.

In your server plug-in function, you can access and modify data in the config pblock structure.

If you need to construct global variables in the plug-in, you can do that in this function. Keep in mind that if you do, and if these variables are changed when the plug-in is called with incoming or outgoing messages, you must synchronize access to them.

For example, this simple version of the initialization function only returns whether or not the function completed.

SAMPLE_EXPORT int SamplePluginInit(pblock *Config){
   return 1;
   }
To see how the initialization function is used in a sample plug-in DLL, see Chapter 4, "Messaging Server Sample Plug-in." For information about stages in message processing, see "How Messaging Server Plug-ins Work."

[Top] [Writing the Initialization and Plug-in Functions]

Writing the Plug-in Function

Your plug-in must export a function based on the pFunc function prototype:

typedef int (*pFunc) (pblock *Config, 
                      struct Message **InMessage,
                      struct Message ***OutMessage);
The Config parameter represents configuration data that is relevant to plug-in operation. It points to the name:value pairs that contain all the optional parameters on the configuration command line. For example, the no-xlate-domains parameter in the example in "How Messaging Server Plug-ins Work" is passed in the parameter block Config.

In your server plug-in function, you can access and modify data in the config pblock structure.

The input-only InMessage parameter represents a pointer to an array of pointers to structures of type Message, terminated by a null pointer. Every pointer to the Message structure represents a separate message. The simplest, and perhaps the most common, case is to place only one pointer in this array.

The OutMessage parameter represents the result of the execution of the site-specific plug-in code. This parameter is required only if the plug-in code generates more than one message from a single input message. The plug-in code should return null in the OutMessage parameter in these cases:

If you split the message into multiple messages, do so immediately after it is received by Messaging Server, at the PostSmtpAccept stage. If the plug-in code does not split the input message (for example, if it encodes the message for all the recipients), the OutMessage output parameter is not necessary.

For return values for this function, see "Plug-in Return Codes."

To see how the plug-in function is used in a sample plug-in DLL, see Chapter 4, "Messaging Server Sample Plug-in." For information about stages in message processing, see "How Messaging Server Plug-ins Work." For information about the Message structure itself, see "The Message Structure."

[Top] [Writing the Initialization and Plug-in Functions]

Plug-in Return Codes

The plug-in code should return one of these codes to Messaging Server. The Messaging Server Plug-in API return messages are listed in "Result Codes."

[Top] [Writing the Initialization and Plug-in Functions]

Using Messaging Server Plug-in Data Structures

Message Server Plug-in functions operate on two fundamental data structures, the pblock parameter block and the Message structure. Many of the functions reference a message Recipient and RecipientList, whose definitions are based on the Address and AddressList structures, respectively.

WARNING: The type definitions are described in this section for informational purposes only. Although your plug-in should be able to reference the members of these structures, it should make all changes through the API, to accommodate future API changes. §
[Top]

The Parameter Block Structure

When Messaging Server calls your plug-in function, it passes a pblock, or parameter block structure, containing server configuration information to the function.

The pblock structure is an array of name:value pairs in a linked list that you can use to set and retrieve control information for a message. Your server plug-in can access and modify data in this parameter block. If you are writing a function that is invoked before the message is handed off to another host immediately after the message is received, at the PostSmtpAccept entry point, you can also stop the message from being sent.

The parameter block is made of name:value pairs keyed on the name string, which maps each name to its value character string.

The pblock structure has this syntax:

typedef struct p_block {
            char *name;
            char *value;
            struct p_block *next;
}
pblock;
The name parameter points to the name portion of the name:value pair, while the value parameter points to the value portion. The next parameter points to the next entry in the linked list of parameter blocks.

To access this structure, use the pblock_findval function.

The functions in Table 2.1 operate on the pblock structure:

Table 2.1 Functions for manipulating the pblock structure  
To do this: Call this function:

Initialize the plug-in.

pInitFunc

Pass the configuration when the plug-in function is called at MTA startup.

pFunc

Find the header line with the given name.

pblock_findval

WARNING: This type definition is for informational purposes only. Although your plug-in should be able to reference the members of these structures, it should make all changes through the API, to accommodate future API changes. §
[Top] [Using Messaging Server Plug-in Data Structures]

The Message Structure

The Message structure stores all attributes that define a single message. This includes control or envelope information, such as envelope sender and recipients, sender and per-recipient extensions, and so on, as well as RFC 822 attributes such as pointers to RFC 822 headers and RFC 822 body.

The Message structure has this syntax:

typedef struct message { 
   long magic;
   char *BaseMsgName;
   char *MsgFileName;
   RecipientList *recipList;
   Sender *sender;
   const char *stage;
   int flags;
   void *context;
   void *control;
}
Message;
To operate on the Message structure or on the Recipient in the Message structure, you can call the functions in Table 2.2:

Table 2.2 Functions for manipulating the Message structure  
To do this: Call this function:

Duplicate the message.

DupMessage

Get the first recipient in the message structure.

GetFirstRecipient

Get the second, third, and all subsequent recipients.

GetNextRecipient

Free the resources associated with a message.

FreeMessage

Get the filename and path to the message file that includes both the header and body.

GetMessageFile

WARNING: This type definition is for informational purposes only. Although your plug-in should be able to reference the members of this structure, it should make all changes through the API, to accommodate future API changes. §
[Top] [Using Messaging Server Plug-in Data Structures]

The Message Recipient and RecipientList Parameters

Many plug-in API functions reference the message recipient, represented by the Recipient parameter, and the RecipientList, represented by the RecipientList parameter. These parameters are defined as types of the Address and AddressList structures, respectively.

[Using Messaging Server Plug-in Data Structures] [The Message Structure]

The Message Recipient and the Address Structure

Many plug-in API functions reference the message recipient, represented by the Recipient parameter. The definition of the recipient is based on the Address structure.

The Address structure has this syntax:

typedef char *N821Address; 
typedef char *SmtpExt;
typedef struct address {
      long magic;
      N821Address Addr821;
      SmtpExt Ext;
      int flags;
} Address;
The definitions of the Recipient and Sender parameters of the Message structure are based on the Address structure.

The functions in Table 2.3 allow access to the recipient list encapsulated in the Message structure:

Table 2.3 Functions for manipulating the Recipient  
To do this: Call this function:

Add a recipient to a message header.

AddRecipient

Get the recipient's email address.

GetRecipientAddress

Get the next recipient in a message header.

GetNextRecipient

Remove a recipient from the recipient list of a message header.

RemoveRecipient

[Using Messaging Server Plug-in Data Structures] [The Message Structure]

The Message RecipientList and the AddressList Structure

Several plug-in API functions reference the list of message recipients, represented by the RecipientList parameter. The definition of the RecipientList is based on the AddressList structure.

The AddressList structure has this syntax:

typedef struct addr_list {
      long magic;
      void *context;
      Address Addr;
      struct addr_list *pNext;
} AddressList;
The RecipientList definition occurs in the API only as a parameter of the Message structure. You have access to RecipientList only through functions that access the Message structure.

typedef AddressList RecipientList; 
[Using Messaging Server Plug-in Data Structures] [The Message Structure]

Using Messaging Server Plug-in Functions

You can use the Messaging Server Plug-in API to perform any of the following operations. Each operation links to a further explanation that includes the function itself.

The examples in the rest of this section demonstrate the operations above in more detail.

To see how these functions are used in a sample plug-in DLL, see Chapter 4, "Messaging Server Sample Plug-in."

[Top]

Find a Messaging Server entry

The pblock_findval function searches the parameter block for the name:value pair with the name given in the name parameter and returns its value or null.

char *pblock_findval(char *name, pblock *pb);
The parameter block, a pblock structure, contains the configuration information for the plug-in.

Duplicate the message

To duplicate an existing Message structure, use DupMessage.

Message *DupMessage (Message *pMessage);
This function creates a new instance of the message in Messaging Server. Messaging Server automatically allocates a message file for the new message and copies the contents of the header and body of the original message. The function returns null if memory failures occur or if the message is not valid.

Free the message

The FreeMessage function frees the resources associated with the message.

void FreeMessage (Message *pMessage);

Get message recipients

To access the recipient list of the input message, use the GetFirstRecipient and GetNextRecipient functions.

GetFirstRecipient gets a pointer to the first recipient in the message.

Recipient *GetFirstRecipient (Message *pMessage); 
GetNextRecipient gets the second, third, and all subsequent recipients.

Recipient *GetNextRecipient (Message *pMessage);

Add and remove recipients

To add or delete recipients on the recipient list, use the AddRecipient or RemoveRecipient function.

int AddRecipient (Message *pMessage,
                  Recipient *pRecipient);
int RemoveRecipient (Message *pMessage, 
                     Recipient *pRecipient);
AddRecipient succeeds if both input parameters are valid and no memory errors occur. RemoveRecipient always succeeds.

This example shows how you can use AddRecipient. First, define the new recipient with any required flags or extension.

new_rcpt.Addr821 = (char*)malloc (strlen ("<testuser@test.com>") + 1);
strcpy(new_rcpt.Addr821, "<testuser@test.com>");
new_rcpt.Ext = NULL;   /* Extension is null */
new_rcpt.flags = 0;    /* No flags used in this example */
Set this required magic value:

new_rcpt.magic = 0xdeadbeef;   /* Use only this magic value */
Make the AddRecipient call. Add the free command to free the recipient when it is finished.

AddRecipient(ppInMsg[0],&new_rcpt); /* Add the new recipient */
free (new_rcpt.Addr821);
To see this sequence as part of a sample plug-in DLL, see Chapter 4, "Messaging Server Sample Plug-in."

Get the recipient's address

To get the RFC 821 address of the recipient, for example, foo@somewhere.org, use GetRecipientAddress.

char *GetRecipientAddress (Recipient *pRecipient);

Get the message file

To find, open, and rewrite or encode the entire message, including its header and body files, use the GetMessageFile function.

char *GetMessageFile (Message *pMessage); 
This function returns the full path to the files that contain the RFC 822 header and body portions of the message. It always succeeds if the message is valid.

NOTE: This function is new in Messaging Server Plug-in API 4.0. It combines the functionality of two 3.0 functions. For more information, see Appendix A, "Converting Messaging Server Plug-in 3.0 Files." §
[Top] [Using Messaging Server Plug-in Functions]

Accessing Control Data

The control data functions of the Messaging Server Plug-in API provide access to the SMTP envelope and connection information gathered during message reception. You can use plug-in functions to perform any of the following operations. Each operation links to a further explanation that includes the function itself.

The examples in the rest of this section demonstrate the operations above in more detail.

To see how these functions are used in a sample plug-in DLL, see Chapter 4, "Messaging Server Sample Plug-in."

NOTE: These functions are new in Messaging Server Plug-in API 4.0. §
[Top]

Get the control data

To get the control data for a message, use the GetControlData function.

char *GetControlData (Message *pMessage); 
This function returns the control data in the form of a character string that contains the full path name to the control data for the message. The character string contains name:value pairs with the elements separated by LFs.

If you change recipients using any if the API functions, this will change the values of the control data that this function retrieves. For this reason, the plug-in should not rely on this information to be up to date.

NOTE: This function is new in Messaging Server Plug-in API 4.0. §
[Top] [Accessing Control Data]

Free the control data

After calling to GetControlData and reviewing the character string returned by it, you must free the control data with the FreeControlData function.

void FreeControlData(char *controldata); 
NOTE: This function is new in Messaging Server Plug-in API 4.0. §
[Top] [Accessing Control Data]

Add the control data

After getting control information, the plug-in can add name:value pairs to the control data.

int AddControlInfo(Message *pMessage, 
                   const char *key,
                   const char *data,
                   int delete_original);
Supply the name portion of the pair in the key parameter and the value portion of the pair in the data parameter. You can delete the original message after adding control data by entering 1 or 0 in the delete_original parameter. This function returns an integer that indicates whether the add operation succeeded. All changes are reflected in any future call to GetControlData.

NOTE: This function is new in Messaging Server Plug-in API 4.0. §
[Top] [Accessing Control Data]

Remove the control data

After getting control data, the plug-in can remove the name:value pair identified by its name portion in the key parameter.

int RemoveControlInfo(Message *pMessage, char *key); 
This function returns an integer that indicates whether the remove operation succeeded. All changes are reflected in any future call to GetControlData.

NOTE: This function is new in Messaging Server Plug-in API 4.0. §
[Top] [Accessing Control Data]


Table of Contents | Previous | Next | Index

Last Updated: 11/19/98 10:35:16

[an error occurred while processing this directive]