Sun Java System Messaging Server 6 2005Q4 MTA Developer's Reference

Chapter 7 Using Callable Send mtaSend()

The Sun Java System Messaging Server MTA Callable Send facility, mtaSend(), is a single procedure that is used to send (enqueue) mail messages of local origin; that is, to originate mail from the local host. Because the mtaSend() routine is not as flexible as the SDK routines and will take possibly undesirable, but necessary, authentication steps (such as, the addition of a Sender: header line), the MTA SDK routines should generally be used by programs that need to resend, forward, send through a gateway, or otherwise route mail messages.

The mtaSend() routine may be used simultaneously with the MTA SDK routines.

This chapter covers the following topics:

Sending a Message

Each message sent with mtaSend() must have a corresponding item list describing the message. The entries in this item list specify the message’s From: and To: addresses as well as input sources for the content of the message.

The basic steps in sending a message with mtaSend() are:

  1. Build an item list to pass to mtaSend().

    To build an item list, complete the following steps:

    1. Specify any special processing options, such as MTA_BLANK, or MTA_IGNORE_ERRORS.

    2. Specify the message’s envelope From: address with the MTA_USER item.

    3. Specify the message’s To:, Cc:, and Bcc: addresses with the MTA_TO, MTA_CC, and MTA_BCC items.

    4. Specify an initial message header in one of two ways:

    5. Specify the input sources for the message body with the MTA_MSG_FILE or MTA_MSG_PROC items.

    6. Terminate the item list with an item code of value 0 (MTA_END_LIST).

  2. Pass the item list to mtaSend().

  3. Check the return status from mtaSend().

    For a description of all item codes and their return status values, see Chapter 8, mtaSend() Routine Specification.

To enqueue additional messages, simply repeat these steps.

Envelope and Header From Addresses

The envelope From: address for a message should be specified with the MTA_USER item code. With this item code, only the local part of a mail address may be specified, that is, the user name. The mtaSend() routine will automatically append the official local host name to the user name so as to produce a valid mail address.

The MTA_ENV_FROM item code may be used to explicitly specify a complete envelope From: address but this is usually not necessary. Applications that enqueue nonlocal mail should probably be using the SDK routines rather than mtaSend().

If neither MTA_USER nor MTA_ENV_FROM are specified, then the user name associated with the current process will be used for the envelope From: address. When MTA_USER is used, the From: header line will be derived from the envelope From: address. When MTA_ENV_FROM is used, the From: header line will be derived from the user name of the current process. In either case, if a From: header line is supplied in an initial header, then a Sender: header line will be added to the message header. The initial From: header line will be left intact and the address specified, and Sender: address will be derived from either the envelope From: address (MTA_USER) or from the user name of the current process, that is, from MTA_ENV_FROM.

Only privileged users may use MTA_USER to specify a user name different than that of the current process. To be considered a “privileged” process on UNIX® systems, the process must have the same (real) user ID (UID) as either the root or Messaging Server account.

To, Cc, and Bcc Addresses

The list of To:, Cc:, and Bcc: addresses to send a message to is built up, one address at a time, with item-list entries. Each item-list entry specifies the type of address (To:, Cc:, or Bcc:) and a string containing the address.

The type of address is denoted by the item code, MTA_TO, MTA_CC, or MTA_BCC, associated with the item-list entry. The mtaSend() routine uses this information to build the message envelope To: address list and To:, Cc:, and Bcc: header.

To specify an envelope-only address that should not appear in the message header (for example, an active transport address), use MTA_ENV_TO. Likewise, to specify a header-only address that should not appear in the envelope, such as, an inactive address, use MTA_HDR_TO, MTA_HDR_CC, or MTA_HDR_BCC, as appropriate.

When one or more of the To:, Cc:, or Bcc: addresses is illegal, the mtaSend() routine will not, by default, indicate which addresses were in error. However, the differentiation can be achieved by using the MTA_ADR_STATUS item code. When this item code is used, the item_status field associated with an address will be set either to zero (0) if the address was accepted, or to a non-zero value if there was an error processing the address.

When item_status is zero, item_smessage points to a NULL terminated string containing the rewritten form of the address. When item_status has a non-zero value, item_smessage points to a NULL terminated string containing an error message suitable for printing for diagnostic purposes.

Message Headers and Content

The body of a message, that is, the message content, is built up from zero or more input files or procedures. The input files and procedures are read or invoked in the order specified in the item list passed to the mtaSend() routine. The message body is built up by appending the next input source to the end of the previous input source. A blank line will be inserted in the message as a separator between input sources if the MTA_BLANK item is requested in the item list. The MTA_MSG_FILE and MTA_MSG_PROC item codes are used to specify the name or address of input files or procedures.

An initial message header may be supplied from either an input file or procedure. The message header will then be modified as needed when the message is enqueued. The MTA_HDR_FILE and MTA_HDR_PROC items are used to specify the name or address of an input file or procedure. If an initial message header is to be supplied, it must appear in the item list before any MTA_MSG_FILE or MTA_MSG_PROC items. A blank line must be supplied at the end of the message header, or at the start of the first message-body input source. This blank line will automatically be supplied when the MTA_BLANK item code is specified in the item list.

The MTA_MODE_ and MTA_ENC_ items control the access mode and encodings applied to message body input sources. These items set the current access mode and encoding to be applied to all subsequent input sources that appear in the item list. The default access mode is MTA_MODE_TEXT, which uses text mode access. The default encoding is MTA_ENC_UNKNOWN, which results in no encoding of the data.

The binary access mode will not be applied to input procedures. The access mode and encoding item codes do not apply to input sources for an initial message header, which is always accessed using the default access mode and never encoded.

Input procedures use the following calling format:

ssize_t proc(const char **bufadr)

where const char **bufadr is the address of pointer to the starting memory location of the next piece of input data.

The return value is ssize_t, which gives the length of the input data. A value that is equal to or greater than zero (0) indicates success. A value of minus one (-1) indicates that there is no further data to return (EOF). Any other negative value indicates an error for which processing should be aborted.

The procedure will be repeatedly called until a negative value is returned, which indicates all input data has been retrieved or an error occurred.

Required Privileges for mtaSend()

Like the MTA SDK routines, privileges are required in order to use mtaSend(). Enqueuing messages requires privileges sufficient to create, open, read from, and write to the MTA message queue directories. On UNIX, this is accomplished by having your executable program owned and run by the MTA account or, alternatively, owned by the MTA and have the setuid attribute set.

In order to submit mail under a user name that differs from that of the calling process, privileges are required. On UNIX platforms, the process must have the same (real) UID as either the root or Messaging Server account.

In some applications, it is important to keep strict control over when privileges are enabled and disabled. To this end, the MTA_PRIV_ENABLE_PROC and MTA_PRIV_DISABLE_PROC item codes may be used to specify the addresses of two procedures to call immediately prior to and immediately after enqueuing a message. This allows the required privileges to be enabled only when they are needed, that is, when the message is enqueued, and to remain disabled at all other times.

The mtaSend() routine does not use a condition handler, so if a fatal error occurs while enqueuing a message, it is up to the calling program to trap the error and, if necessary, disable any privileges that should be disabled. These procedures, if specified, should accept no arguments and return no function result (return value).

The privileges to be enabled must either be granted to the program using mtaSend() (for example, the program may have been installed with privileges), or the process running the program must have the requisite privileges. The mtaSend() routine and the MTA do not provide these privileges.

mtaSendDispose()

For each call to mtaSend() where MTA_ADR_STATUS is used, there should be a subsequent call to mtaSendDispose().

Syntax

void mtaSendDispose(mta_item_list_t *item_list)

Arguments

Argument  

Description  

item_list

Pointer to an array with elements of type mta_item_list_t. This should be an array previously passed to mtaSend().

Description

Each call to this routine disposes of virtual memory allocated by mtaSend() for returning address status information requested with the MTA_ADR_STATUS item code.

Return Values

None

Example


...
item_list[index++].item_code=MTA_ADR_STATUS;
item_list[index++].item_code=MTA_ITEM_END;
istat=mtaSend(item_list);
...
mtaSendDispose(item_list);

Compiling and Linking Programs

Programs that use mtaSend() are linked using the same steps as the MTA SDK routines. For details, see Chapter 2, MTA SDK Programming Considerations.

Examples of Using mtaSend()

Several example programs, written in C, are provided in this section:

The example routines shown in this section may be found in the examples/mta/sdk directory.

Sending a Simple Message

The program shown in Example 7–1 demonstrates how to send a simple message to the root account. The source code itself is used as the input source for the body of the message to be sent. The From: address associated with the message is that of the process running the program. Comments in the program example explain the sample output line they generate.


Example 7–1 Send a Simple Message


/* send_simple.c Send a simple message */
#include <string.h\>
#include "mtasdk.h"

/* Push an entry onto the item list */
#define ITEM(item,adr) item_list[index].item_code = item;\
  item_list[index].item_address = adr;\
  item_list[index].item_length  = adr ? strlen(adr) : 0; \
  item_list[index].item_status  = 0;\
  item_list[index++].item_smessage = NULL

main ()
{
  mta_item_list_t item_list[4];
  int index = 0;

  ITEM(MTA_TO, "root"); /* Becomes the To: line in the output */
  ITEM(MTA_SUBJECT, "send_simple.c");
  ITEM(MTA_MSG_FILE, __FILE__);/* Becomes the Subject: line */
  ITEM(MTA_END_LIST, 0);
  exit(mtaSend(item_list));
}

Output for Example 1 Sending a Simple Message


Date: 04 Oct 1992 22:24:07 -0700 (PDT)
From: jdoe@sesta.com
Subject: send_simple.c
To: root@sesta.com
Message-id: <01GPKF10JIB89LV1WX@sesta.com\>
MIME-version: 1.0
Content-type: TEXT/PLAIN; CHARSET=US-ASCII
Content-transfer-encoding: 7BIT

/* send_simple.c -- Send a simple message */
#include <string.h\>
#include "mtasdk.h"

...

Example 2 Specifying an Initial Message Header

The program shown in Example 7–2 illustrates the use of the MTA_HDRMSG_FILE and MTA_HDR_ADRS item codes to enqueue a message that has already been composed, including the headers, and stored in a file. The input file is given in the Input File for Example 2 Specifying an Initial Message Header. The resulting message is shown in Output for Example 2 Specifying an Initial Message Header.

When the entire message, header and body, is contained in a single file, use the MTA_HDRMSG_FILE item code in place of the MTA_HDR_FILE and MTA_MSG_FILE item codes.


Example 7–2 Specify an Initial Message Header


/* send_header.c -- Send a message with initial header */
#include <string.h\>
#include "mtasdk.h"

/* Push an entry onto the item list */
#define ITEM(item,adr) item_list[index].item_code = item;\
  item_list[index].item_address = adr;\
  item_list[index].item_length  = adr ? strlen(adr) : 0;\
  item_list[index].item_status  = 0;\
  item_list[index++].item_smessage = NULL

main ()
{
  MTA_item_list_t item_list[3];
  int index = 0;

  ITEM(MTA_HDR_ADRS, 0);
  ITEM(MTA_HDRMSG_FILE, "send_header.txt");
  ITEM(MTA_END_LIST, 0);
  exit(mtaSend(item_list));
}

            

Input File for Example 2 Specifying an Initial Message Header


Subject: MTA SDK callable Send example
To: root@sesta.com
MIME-version: 1.0
Content-type: TEXT/PLAIN; CHARSET=US-ASCII
Content-transfer-encoding: 7BIT
Comments: Ignore this message -- it’s just a test

This is a test of the emergency broadcasting system!

1234567890123456789012345678901234567890123456789012345678901234
5678901234567890

0000000001111111111222222222233333333334444444444555555555566666
6666677777777778

Output for Example 2 Specifying an Initial Message Header


Date: 04 Jan 2003 22:42:25 -0800 (PST)
From: system@sesta.com
Subject: MTA SDK callable Send example
To: system@sesta.com
Message-id: <01GPKFNPUQF89LV1WX@sesta.com\>
MIME-version: 1.0
Content-type: TEXT/PLAIN; CHARSET=US-ASCII
Content-transfer-encoding: 7BIT
Comments: Ignore this message -- it’s just a test

This is a test of the emergency broadcasting system!

1234567890123456789012345678901234567890123456789012345678901234
5678901234567890

0000000001111111111222222222233333333334444444444555555555566666
6666677777777778

Example 3 Sending a Message to Multiple Recipients

The program given in Example 7–3 demonstrates the following points:

The message is sent to one To: address, a Cc: address, and a Bcc: address. After mtaSend() is called, any status message associated with each address is displayed.

The log output produced by running the program is shown in Output for Example 3 Sending a Message to Multiple Recipients.

The following items of note are identified in the comments in the program:


Example 7–3 Sending a Message to Multiple Recipients


/* send_multi.c -- Send a message to multiple recipients */
#include <stdio.h\>
#include <string.h\>
#include "mtasdk.h"

#define ITEM(item,adr) item_list[index].item_code = item;\
  item_list[index].item_address = adr;\
  item_list[index].item_length  = adr ? strlen(adr) : 0;\
  item_list[index].item_status  = 0;\
  item_list[index++].item_smessage = NULL

main ()
{
  int index = 0, istat, i;
  mta_item_list_t item_list[7];

  /* Specify the Subject: header line and message input source */
  ITEM(MTA_SUBJECT, "send_multi.c");
  ITEM(MTA_MSG_FILE, __FILE__);

  /* Return per address status/error messages */
  ITEM(MTA_ADR_STATUS, 0); /* Instructs mtaSend() to return a */
                           /* status message for each envelope */
                           /* recipient address                */

  /* Specify regular Bcc:, To:, and Cc: addresses */
  ITEM(MTA_BCC, "root");
  ITEM(MTA_TO, "abuse@sample.com");
  ITEM(MTA_CC, "postmaster@sample.com");

  /* Now terminate the item list */
  ITEM(MTA_END_LIST, 0);

  /* And send the message */
  istat = mtaSend(item_list);/* Sends the message. */

  /* Display the address status messages provided that no */
  /* error other than MTA_HOST has occurred               */



  for (i = 0; i < index; i++) /* Display any returned status */
                              /* messages                    */
       if (item_list[i].item_smessage)
           printf ("%s: %s - %s\n",
                   (const char *)item_list[i].item_address,
                   item_list[i].item_status ? "Failed" :
                                              "Succeeded",
                   item_list[i].item_smessage);

  /* Dispose of status messages */
  mtaSendDispose(item_list);
  exit(istat);
}

Output for Example 3 Sending a Message to Multiple Recipients


Succeeded: root@sample.com
Succeeded: abuse@sample.com
Succeeded: postmaster@sample.com

Example 4 Using an Input Procedure to Generate the Message Body

The program shown in Example 7–4 uses an input procedure as the source for the body of a message to be sent. In the program, the input procedure msg_proc will read input until the runtime library routine fgets() signals an EOF condition, for example, a control-D has been input. The address of the procedure msg_proc is passed to mtaSend() using a MTA_MSG_PROC item code. The mtaSend() routine repeatedly calls the msg_proc procedure, until a negative value is returned by the procedure.


Example 7–4 Using an Input Procedure to Generate the Message Body


/* send_input.c -- Demonstrate the use of MTA_MSG_PROC */
#include <stdio.h\>
#include <stdlib.h\>
#include <string.h\>
#include "mtasdk.h"
#ifdef _WIN32
typedef long ssize_t;
#endif

/* Push an entry onto the item list */
#define ITEM(item,adr) item_list[index].item_code = item;\
item_list[index].item_address = adr;\
item_list[index].item_length  = 0;\
item_list[index].item_status  = 0;\
item_list[index++].item_smessage = NULL

ssize_t msg_proc(const char **bufadr)
{
  static char buf[1024];

  if (!bufadr)
      return(-2); /* Call error; abort */

  printf("input: ");
  if (fgets(buf, sizeof(buf), stdin))
  {
    *bufadr = buf;
    buflen = strlen(buf);
    if (buf[buflen-1] == ’\n’)
      buflen -= 1;
    return(buflen);
  }
  else
    return(-1);  /* EOF */
}

main ()
{
  int istat, index = 0;
  mta_item_list_t item_list[4];

  STRITEM(MTA_SUBJECT, "send_input.c");
  STRITEM(MTA_TO, "root");
  ITEM(MTA_MSG_PROC, msg_proc);
  ITEM(MTA_END_LIST, 0);
  exit(mtaSend(item_list));
}