Skip to content

Sending and Receiving Mail

Chapter 10-3
Sending and Receiving Mail

This chapter explains how to use NSF functions and Mail Gateway API functions to send and receive Domino mail messages.

Sending Mail

The required steps for sending a document using the HCL C API for Domino and Notes are:

  1. Create a document in the mail.box file on a Domino mail server or locally.
  2. Append a valid Recipients field to the document.
  3. Update the document in an active mail.box file.


For details about what constitutes a valid Recipients field, see the "Domino Mail Architecture" chapter. The Recipients field is the only field required by the router. The document may contain any number of other fields.

Most mail programs perform more than the minimum steps listed above. Typical mail messages contain fields named From, SendTo, Subject, Date, and Body. The example mail programs described below append these other items to the document before sending the document as a mail message.


Example Using NSF Functions

The sample program SENDMEMO, a standalone API program, uses NSF functions to create and send a mail message.

SENDMEMO is a character-mode program. Its source code is in the directory \samples\mail\sendmemo.

SENDMEMO: Initialization

SENDMEMO uses the following algorithm:

  1. Obtain SendTo, Subject, and Body from the command line.
  2. Use SECKFMUserInfo to obtain the name of the user running the program. Use this name in the From field.
  3. Use OSGetEnvironmentString to get the name of the mail server from the environment variable "MailServer" stored in notes.ini.
  4. Use OSGetEnvironmentInt to see if, in the event of multiple mail.box files, the "mail.box" is active.
  5. Use OSPathNetConstruct to construct the network path to a mail.box file.
  6. Call NSFDbOpen to open the mail file on the mail server or locally. This yields <hMailBox>, the handle to the open mail box.
  7. Get the current time/date to use in the ComposedDate item.
  8. Call NSFNoteCreate to create a message document in the mail file. This yields <hMemo>, the handle to the message document.
sendmemo.c - Initialization Steps

int main(int argc, char * argv[])
{
   STATUS      error = NOERROR;
   char       szSendTo;
   char      
szSubject;
   char       szBody;
   char        szFrom[MAXUSERNAME+1];
   char        szMailServerName[MAXUSERNAME+1];
   char        szMailFileName[MAXUSERNAME+1] = MAILBOX_NAME;
   char        szMailBoxPath[MAXPATH+1];
   DBHANDLE    hMailBox;
   NOTEHANDLE  hMemo;
   TIMEDATE    tdCurrent;
   BLOCKID     bidItem;
   WORD        wDataType;
   BLOCKID     bidValue;
   DWORD       dwValueLen;
   HANDLE      hRichTextBody;
   DWORD       dwRichTextLen;
   BYTE      
pRichTextBody;


    if (argc != 4)
   {
       printf ("Error: incorrect syntax.\n");
       printf ("%s  \"to\" \"subject\" \"body\"\n", argv[0]);
       return (NOERROR);
   }
   szSendTo = argv[1];
   szSubject = argv[2];
   szBody = argv[3];


if (error = NotesInitExtended (argc, argv))
    {
        printf("\n Unable to initialize Notes.\n");
        return (1);
    }

    if (error = SECKFMUserInfo(KFM_ui_GetUserInfo, szFrom, NULL))
   {
       printf ("Error: unable to get user name.\n");
       
goto Done;
   }
   if (!OSGetEnvironmentString("MAILSERVER", szMailServerName, MAXUSERNAME))
   {
       printf ("\nUnable to get mail server name ...\n\n Adding message local 'mail.box' file ...\n\n");
       strcpy(szMailServerName,"");


        / In the event of multiple "mail.box" files, if the NOTES.INI parameter
       "MAIL_ENABLE_MAILBOX_COMPATIBILITY =1" is set, then the file "mail.box" will be used,
       otherwise "mail2.box" will be used.
/
       if (!OSGetEnvironmentInt("MAIL_ENABLE_MAILBOX_COMPATIBILITY"))
       {
          printf ("\nEnable mailbox parameter is not set ...\n\n Adding message to local 'mail2.box' file ...\n\n");
          strcpy(szMailFileName, "mail2.box");
       }
   }


    / In the event of multiple "mail.box" databases, ensure message is successfully deposited. /
   do
   {
       OSPathNetConstruct( NULL,               / port name  /
                           szMailServerName,
                           szMailFileName,
                           szMailBoxPath);


        if (error = NSFDbOpen (szMailBoxPath, &hMailBox))
       {


            / If multiple mail.box files do not exist, place memo in standard "mail.box" file. /
           if ((error == ERR_NOEXIST) && (!strcmp (szMailFileName, "mail2.box")))
           {
              strcpy(szMailFileName, "mail.box");
           }
           else
           {
              printf ("Error: unable to open '%s'.\n", szMailBoxPath);
             
goto Done;
           }
       }
   }
   while (error);


    OSCurrentTIMEDATE(&tdCurrent);

    if (error = NSFNoteCreate(hMailBox, &hMemo))
   {
       printf ("Error: unable to create memo in %s.\n", szMailBoxPath);
       
goto Done1;
   }


SENDMEMO: Form, SendTo, and Recipients

After obtaining all the inputs and creating a document in a mail.box file, SENDMEMO appends data items to the document, including the Form, SendTo, and Recipients fields.

  1. Append the Form item to the document. The standard memo form is Memo.
  2. Append the SendTo item (obtained from the command line) to the document.
  3. Call NSFItemSetText to append the Recipients item to the message. If more than one recipient were supported, you would need to call NSFItemCreateTextList.
sendmemo.c - Form, SendTo, and Recipients Items


    if (error = NSFItemSetText( hMemo,
                               FIELD_FORM,     / "Form" /
                               MAIL_MEMO_FORM, / "Memo" = Standard memo /
                               MAXWORD))
   {
       printf ("Error: unable to set item '%s' into memo.\n", FIELD_FORM);
       
goto Done2;
   }


    if (error = NSFItemSetText( hMemo,
                               MAIL_SENDTO_ITEM,  / "SendTo" /
                               szSendTo,
                               MAXWORD))
   {
       printf ("Error: unable to set item '%s' into memo.\n",
       
goto Done2;
   }


    if (error = NSFItemSetText( hMemo, / use NSFItemCreateTextList if > 1/
                               MAIL_RECIPIENTS_ITEM,   / "Recipients" /
                               szSendTo,
                               MAXWORD))
   {
       printf ("Error: unable to set item '%s' into memo.\n",
                               MAIL_RECIPIENTS_ITEM);
       
goto Done2;
   }

    For simplicity, SENDMEMO assumes that the SendTo string specified on the command line constitutes a valid Recipients field. More sophisticated mail programs might parse the specified string to handle multiple recipients. To handle more than one recipient, the Recipients field must be a text list field. Also, more sophisticated mail programs should verify that the SendTo string matches a name in the Domino Directory. Note that SENDMEMO does not check the SendTo field.

    SENDMEMO: The Body Field

      1. Append the following fields to the document:
        - From
        - Subject
        - DeliveryPriority
        - DeliveryReport
        - ReturnReceipt
        - ComposedDate
        The source code for this step is not shown here.
      2. Create a rich text body item by first creating a temporary text body item, then converting the item to type composite. Append the composite item to the document as the Body field, then delete the temporary text item.
        sendmemo.c - The Body Field

          if (error = NSFItemSetText( hMemo,
                                     TEMP_MAIL_BODY_ITEM,  / "TempBody" /
                                     szBody,
                                     MAXWORD))
         {
             printf ("Error: unable to set item '%s' into memo.\n",
                                     TEMP_MAIL_BODY_ITEM);
             
      goto Done2;
         }


          if (error = NSFItemInfo(hMemo,
                                 TEMP_MAIL_BODY_ITEM,
                                 strlen(TEMP_MAIL_BODY_ITEM),
                                 &bidItem, &wDataType, &bidValue, &dwValueLen))
         {
             printf ("Error: unable to get info re item '%s'.\n",
                                 TEMP_MAIL_BODY_ITEM);
             
      goto Done2;     
         }


          if (error = ConvertItemToComposite(bidValue, dwValueLen,
                     DEFAULT_FONT_ID, "", PARADELIM_BLANKLINE,
                     &hRichTextBody, &dwRichTextLen,
                     FALSE, NULL, 0, FALSE))
         {
             printf ("Error: unable to convert text item to composite.\n");
             
      goto Done2;   
         }


          pRichTextBody = OSLockObject(hRichTextBody) ;
         pRichTextBody += sizeof(WORD);
         dwRichTextLen -= sizeof(WORD);


          if (error = NSFItemAppend(hMemo, 0, MAIL_BODY_ITEM,
                         strlen(MAIL_BODY_ITEM), TYPE_COMPOSITE, pRichTextBody,
                         dwRichTextLen))
         {
             printf ("Error: unable to append item '%s' to note.\n",
                                 MAIL_BODY_ITEM);
             OSUnlockObject(hRichTextBody);

      OSMemFree(hRichTextBody);
              goto Done2;     
         }
             
         OSUnlockObject(hRichTextBody) ;

          OSMemFree(hRichTextBody);

          if (error = NSFItemDelete(hMemo, TEMP_MAIL_BODY_ITEM,
                                 strlen(TEMP_MAIL_BODY_ITEM)))
         {
             printf ("Error: unable to delete item '%s' to note.\n",
                                 TEMP_MAIL_BODY_ITEM);
             
      goto Done2;         
         }


      Note that the technique SENDMEMO uses to create a rich text Body field only works if the resulting message body is smaller than 64 kilobytes. Also, it creates a Body field that contains only text, with no bitmaps, tables, or links.

      SENDMEMO: Transfer to the Router

      1. Use NSFNoteUpdate to update the document to the mail.box file. This transfers the document to the router.
      2. Close the document.
      3. Close the mail.box file.
      sendmemo.c - Transfer to the Router

          if (error = NSFNoteUpdate(hMemo, 0))
         {
             printf ("Error: unable to update note in mail.box.\n");
             
      goto Done2; 
         }


      Done2:
          NSFNoteClose(hMemo);

      Done1:
          NSFDbClose(hMailBox);

      Done:
          if (error)
            PrintAPIError (error);  
          else
              printf ("%s: successfully deposited memo '%s' in '%s'.\n",
                      argv[0], szSubject, szMailBoxPath);

          NotesTerm();
          return (error);
      }

        Note that a mail program of any greater complexity than SENDMEMO should create the document first in a local database, open the mail.box file, copy the message document to the mail.box file, and close the mail.box file as soon as possible. API programs should keep the mail.box file open for a minimum amount of time.


        Example Using Mail Gateway API Functions

        The sample program SENDMAIL sends a Mail message using primarily Domino Mail Gateway API functions, along with a few NSF functions.

        SENDMAIL is a standalone API program.

        The source code for SENDMAIL resides in the appropriate platform directory in the subdirectory \samples\mail\sendmail.

        The Domino Mail Gateway API functions help to make the algorithm for SENDMAIL simpler than the algorithm for SENDMEMO.

        SENDMAIL differs from SENDMEMO in the following ways:

        • SENDMAIL creates the document in the user's message file. It appends all the fields to the document before opening the mail.box file. This allows SENDMAIL to open the mail.box file, copy the document into the mail.box file, and close the mail.box file with the minimum number of intermediate steps.
        • SENDMAIL saves the document in the user's message file, as well as sending it via the Domino router.
        • SENDMAIL handles the case where the workstation running the program is not connected directly to the mail server by a LAN. If the LAN is not available, SENDMAIL copies the document into a local copy of the mail.box file for later delivery to the router.
        • SENDMAIL handles multiple names in the SendTo and CopyTo fields. It creates SendTo, CopyTo, and Recipients fields as text lists. However, like SENDMEMO, SENDMAIL does not look up the names provided as input to verify that they exist in the Domino Directory.


        SENDMAIL: Creating the Recipients field

        The code fragment below shows how SENDMAIL handles the SendTo and Recipients fields as text lists.

        sendmail.c - Recipients as a Text List Field

            if (status = ListAllocate(0, 0, TRUE, &hRecipientsList,
                       &plistRecipients, &wRecipientsSize))
           {
               / Unable to allocate list /
               error = ERR_SENDMAIL_CANTALLOCATELIST;
               goto CloseMsg;
           }
           OSUnlockObject(hRecipientsList);


            if (status = ListAllocate(0, 0, TRUE, &hSendToList,
                       &plistSendTo, &wSendToSize))
           {
               error = ERR_SENDMAIL_CANTALLOCATELIST;
               goto CloseMsg;
           }
           OSUnlockObject(hSendToList);


        / ... code omitted .../  

           / Parse SendTo string. Add names to SendTo and Recipients lists. /

            for (szNextName = strtok(szSendTo, ":,");
                szNextName != (char)NULL;
                szNextName = strtok(NULL, ":,"))
           {
               while (isspace(
        szNextName))    // Skip white space before name
                   szNextName++;


                if (status = ListAddEntry(hSendToList, TRUE, &wSendToSize,
                                       wSendToCount++, szNextName,
                                       (WORD)lstrlen(szNextName)))
               {   / Unable to add name to SendTo list /
                   error = ERR_SENDMAIL_CANTADDTOSENDLIST;
                   goto CloseMsg;
               }


                if (status = ListAddEntry(hRecipientsList, TRUE, &wRecipientsSize,
                                       wRecipientsCount++, szNextName,
                                       (WORD)lstrlen(szNextName)))
               {   / Unable to add name to Recipients list /
                   error = ERR_SENDMAIL_CANTADDTORECIPLIST;
                   goto CloseMsg;
               }
           }


        / ... code omitted .../

            if (status = MailAddRecipientsItem( hMsg, hRecipientsList,
                                               wRecipientsSize))
           {
               / Unable to set Recipient item in memo /
               error = ERR_SENDMAIL_CANTSETRECIPIENT;
               goto CloseMsg;
           }
           /  MailAddRecipientsItem and MailAddHeaderItemByHandle both attach
               the memory used by the list to the message. Set handle to NULL
               after these functions succeed so the code at CloseMsg: below does
               not attempt to free it.
           
        /
           hRecipientsList = NULLHANDLE;



        Enhancing Mail Applications

          You may wish to enhance your mail programs by looking up in the Domino Directory each name provided as input, to ensure that the name is a valid recipient. Your mail program is responsible for building a valid list of recipients. The following suggestions may help you implement these enhancements:

          • You may want to use NAMELookup if you don't know whether a name is a user or a group.
          • Add names with explicit path routing (for example, "Sally@Z@Y") directly to the Recipients list without attempting to look them up.
          • Look up other names to make sure they exist in one of the Domino Directories. Do not add names to the Recipients list if they cannot be found in the Domino Directory. You may wish to resolve unfound names by interacting with the user.
          • To eliminate duplicates, you must expand all group names. Otherwise, you may place group names in the Recipients list as long as the group name is defined in the Local Address Book(s).
          • Expand names of recipients in foreign domains to a mail address in NAME@DOMAIN format. If your application is running on a server, you can use MailLookupAddress to do this. Otherwise, use NAMELookup. Do not alter the case of the domain name, since the router is case-sensitive for domain names.
          • Build a multi-valued text list of recipients by calling the Mail Gateway API function MailAddRecipients to add each expanded recipient name (referred to as a "full mail address") to the Recipients list.


            Receiving Domino Mail

            Receiving mail consists of opening the appropriate mail file and reading the documents in it. The router delivers messages to mail files, which are databases identified in the Domino Directory as belonging to a given user. Therefore, to receive mail documents, an API program simply opens the appropriate mail file and reads the documents it contains.


            Example Using Mail Gateway API Functions

            The Domino Mail Gateway API contains a number of functions that help you read, create, and manage large numbers of document in mail files. The Mail Gateway API provides functions that create and manage lists of documents.

            READMAIL

            The sample program READMAIL reads all the messages in a specified mail file and prints them on the screen.

            The source code for READMAIL is in the directory \samples\mail\readmail. READMAIL uses primarily Domino Mail Gateway API functions.

            MGATE Outbound

            The sample program MGATE is an example Domino Mail Gateway built as a server add-in task. The outbound module of MGATE shows how to use Domino Mail Gateway API routines to read and process documents in a mail file.

            The source code for the outbound portion of MGATE is in the file outbound.c in the directory \samples\server\mgate