eMail

Some articles about how to send, or read e-mail from within Progress


a MAPI approach with one attachment

This solution is made by Johann van der Merwe.
It allows one attachment.

{windows.i}
 
RUN mapi ( "you@work.com",
           "yourwife@home.com",
           "late for dinner",
           "something came up..",
           "c:\images\flowers.bmp"
          ).
 
 
/* ========================================================================== */
 
PROCEDURE MAPI :
 
DEFINE INPUT PARAMETER OriginName   AS CHARACTER.
DEFINE INPUT PARAMETER RecipName    AS CHARACTER.
DEFINE INPUT PARAMETER Subject      AS CHARACTER.
DEFINE INPUT PARAMETER Bodytext     AS CHARACTER.
DEFINE INPUT PARAMETER FilePathName AS CHARACTER.
 
 
DEFINE VARIABLE SubjPtr AS MEMPTR.
SET-SIZE(SubjPtr) = LENGTH(Subject) + 1. /* maximum = 255 */ 
PUT-STRING(SubjPtr,1) = Subject.
DEFINE VARIABLE TextPtr AS MEMPTR.
SET-SIZE(TextPtr) = 16000. 
PUT-STRING(TextPtr,1) = Bodytext + (IF FilePathName = "":U 
                                    THEN "":U 
                                    ELSE CHR(10) + CHR(10) + " ":U).   
/* if file attached place at end of Bodytext with line skip */
 
/* ---------------- Build Originator details ------------------------ */
DEFINE VARIABLE OriginNamePtr AS MEMPTR.
SET-SIZE(OriginNamePtr) = LENGTH(OriginName) + 1.  /* maximum = 255 */
PUT-STRING(OriginNamePtr,1) = OriginName.  /* Originator name */
 
DEFINE VARIABLE OriginDescPtr AS MEMPTR.
SET-SIZE(OriginDescPtr) = 24.
PUT-LONG(OriginDescPtr,1) = 0. /* Reserved */ 
PUT-LONG(OriginDescPtr,5) = 0. /* RecipClass 0 = MAPI_ORIG */ 
PUT-LONG(OriginDescPtr,9) = GET-POINTER-VALUE(OriginNamePtr).  /* Name */
PUT-LONG(OriginDescPtr,13) = 0. /* Address */ 
PUT-LONG(OriginDescPtr,17) = 0. /* EID Size */ 
PUT-LONG(OriginDescPtr,21) = 0. /* Entry ID */
 
/* ----------------Build Recipient details -------------------------- */
DEFINE VARIABLE RecipNamePtr AS MEMPTR.
SET-SIZE(RecipNamePtr) = LENGTH(RecipName) + 1./* maximum = 255 */ 
PUT-STRING(RecipNamePtr,1) = RecipName. /* Recipient name */
DEFINE VARIABLE RecipDescPtr AS MEMPTR.
SET-SIZE(RecipDescPtr) = 24.
PUT-LONG(RecipDescPtr,1) = 0. /* Reserved */ 
PUT-LONG(RecipDescPtr,5) = 1. /* RecipClass 1 = MAPI_TO */ 
PUT-LONG(RecipDescPtr,9) = GET-POINTER-VALUE(RecipNamePtr).  /* Name */
PUT-LONG(RecipDescPtr,13) = 0. /* Address */ 
PUT-LONG(RecipDescPtr,17) = 0. /* EID Size */ 
PUT-LONG(RecipDescPtr,21) = 0. /* Entry ID */
 
/* --------------- Build File Details ------------------- */
IF FilePathName <> "":U THEN DO:
   DEFINE VARIABLE FilePathNamePtr AS MEMPTR.
   SET-SIZE(FilePathNamePtr) = LENGTH(FilePathName) + 1.  /* maximum = 255 */
   PUT-STRING(FilePathNamePtr,1) = FilePathName.  /* File pathname */
 
   DEFINE VARIABLE FILENAME AS CHARACTER NO-UNDO.
   FILENAME = SUBSTRING(FilePathName,R-INDEX(FilePathName,"\":U) + 1).
   /* extract filename (starting on last \) from filefullname */
   FILENAME = "     ":U + FILENAME.
   /* for some strange reason the first five chars disappear */
 
   DEFINE VARIABLE FileNamePtr AS MEMPTR.
   SET-SIZE(FileNamePtr) = LENGTH(FILENAME) + 1. /* maximum = 255 */ 
   PUT-STRING(FileNamePtr,1) = FILENAME. /* File name */
 
   DEFINE VARIABLE FileDescPtr AS MEMPTR.
   SET-SIZE(FileDescPtr) = 24.
   PUT-LONG(FileDescPtr,1) = 0. /* Reserved */ 
   PUT-LONG(FileDescPtr,5) = 0. /* Flags 0 = data file */
   PUT-LONG(FileDescPtr,9) = LENGTH(Bodytext) + 2.  /* Position */
   PUT-LONG(FileDescPtr,13) = GET-POINTER-VALUE(FilePathNamePtr).  /* PathName */
   PUT-LONG(FileDescPtr,17) = GET-POINTER-VALUE(FileNamePtr). /* FileName */ 
   PUT-LONG(FileDescPtr,21) = 0. /* FileType */
END.
 
 
 
/* ---------- Build Message Details ------------------- */
DEFINE VARIABLE MessageDescPtr AS MEMPTR.
SET-SIZE(MessageDescPtr) = 48.
PUT-LONG(MessageDescPtr,1) = 0.  /* Reserved */
PUT-LONG(MessageDescPtr,5) = GET-POINTER-VALUE(SubjPtr).  /* Subject */
PUT-LONG(MessageDescPtr,9) = GET-POINTER-VALUE(TextPtr).  /* Text */
PUT-LONG(MessageDescPtr,13) = 0. /* MessageType */ 
PUT-LONG(MessageDescPtr,17) = 0. /* DateReceived */ 
PUT-LONG(MessageDescPtr,21) = 0. /* ConversationID */ 
PUT-LONG(MessageDescPtr,25) = 1.  /* Flags */
PUT-LONG(MessageDescPtr,29) = GET-POINTER-VALUE(OriginDescPtr).  /* Originator */
PUT-LONG(MessageDescPtr,33) = 1.  /* RecipCount */
PUT-LONG(MessageDescPtr,37) = GET-POINTER-VALUE(RecipDescPtr).  /* Recips */
PUT-LONG(MessageDescPtr,41) = (IF FilePathName = "":U 
                                  THEN 0 
                                  ELSE 1).  /* FileCount */
PUT-LONG(MessageDescPtr,45) = (IF FilePathName = "":U 
                                  THEN 0 
                                  ELSE GET-POINTER-VALUE(FileDescPtr)).                             /* Files */
/* EO Build Message Details */
 
 
/* -------- Send Message ------------ */
DEFINE VARIABLE ResultInt AS INTEGER NO-UNDO.
RUN MAPISendMail IN hpApi
 (INPUT 0,
  INPUT 0,
  INPUT GET-POINTER-VALUE(MessageDescPtr),
  INPUT 11, /* 1 = MAPI_LOGON_UI + 2 = MAPI_NEW_SESSION + 8 = MAPI_DIALOG */
  INPUT 0,     
  OUTPUT ResultInt). 
 
RUN MapiReturnCode (ResultInt).
 
/* ------- Free memory ------------ */
SET-SIZE(SubjPtr)         = 0.
SET-SIZE(TextPtr)         = 0. 
SET-SIZE(OriginNamePtr)   = 0.
SET-SIZE(OriginDescPtr)   = 0.
SET-SIZE(RecipNamePtr)    = 0.
SET-SIZE(RecipDescPtr)    = 0.
SET-SIZE(FilePathNamePtr) = 0.
SET-SIZE(FileNamePtr)     = 0.
 
END PROCEDURE.

= A Simple MAPI Approach, Multiple Attachments and Recipients

=
This solution is by Ian Richards. A COM solution is easier, but this allows me to send automated e-mails from a server where Outlook is not installed. The recipients and attachments are presented as comma separated lists.

{windows.i}
 
RUN mapimulti( 
  INPUT "you@originator.com",
  INPUT "recipient1@address1.com,recipient2@address2.com",
  INPUT "Message Title",
  INPUT "Message Text",
  INPUT "C:\file1.txt,C:\file2.txt").
/* ========================================================================== */
PROCEDURE mapimulti:
{windows.i}
DEFINE INPUT PARAMETER ipOrigName     AS CHARACTER NO-UNDO.                 /* Originator Name */
DEFINE INPUT PARAMETER ipRecipName    AS CHARACTER NO-UNDO.                 /* Recipient(s) names, comma separated */
DEFINE INPUT PARAMETER ipSubject      AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER ipBodytext     AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER ipFilePathName AS CHARACTER NO-UNDO.                 /* Attachment(s) names, comma separated */ 
DEFINE VARIABLE intRecips AS INTEGER NO-UNDO.                               /* Count Recipients */
DEFINE VARIABLE intAttachs AS INTEGER NO-UNDO.                              /* Count Attachments */
DEFINE VARIABLE RecipName AS CHARACTER EXTENT 20 NO-UNDO.                   /* Recipient Array */
DEFINE VARIABLE FilePathName AS CHARACTER EXTENT 20 NO-UNDO.                /* Attachment Array */ 
/* Memptr Definitions */
DEFINE VARIABLE SubjPtr AS MEMPTR NO-UNDO.                                  /* Message Subject */
DEFINE VARIABLE TextPtr AS MEMPTR NO-UNDO.                                  /* Message Text */
DEFINE VARIABLE OriginNamePtr AS MEMPTR.                                    /* Originator Name */
DEFINE VARIABLE RecipNamePtr AS MEMPTR EXTENT 20 NO-UNDO.                   /* Array of pointers to Recipient Name */
DEFINE VARIABLE RecipDescPtr AS MEMPTR EXTENT 20 NO-UNDO.                   /* Array of pointers to Recipient Description */
DEFINE VARIABLE FilePathNamePtr AS MEMPTR EXTENT 20 NO-UNDO.                /* Array of pointers to Attachment Path */
DEFINE VARIABLE FileNam AS CHARACTER EXTENT 20 NO-UNDO.                     /* Array of Attachment Name */
DEFINE VARIABLE FileNamPtr AS MEMPTR EXTENT 20 NO-UNDO.                     /* Array of pointers to Attachment Name */
DEFINE VARIABLE FileDescPtr AS MEMPTR EXTENT 20 NO-UNDO.                    /* Array of pointers to Attachment Description */ 
DEFINE VARIABLE MessageDescPtr AS MEMPTR NO-UNDO.                           /* Pointer To Message Structure */
DEFINE VARIABLE FileArrayPtr AS MEMPTR NO-UNDO.                             /* Pointer to Array of File Decription */
DEFINE VARIABLE RecipArrayPtr AS MEMPTR NO-UNDO.                            /* Pointer to Array of Recipient */
DEFINE VARIABLE zz AS INTEGER NO-UNDO.                                      /* General Purpose Integer */
/* --- POPULATE RECIPIENT & ATTACHMENT ARRAYS -------*/
RUN recips.     /* Populate RecipName */
RUN attachs.    /* Populate FilePath Name */
                                                                                
/* --- SET MESSAGE TEXT AND SUBJECT -----------------*/
SET-SIZE(SubjPtr) = LENGTH(ipSubject) + 1.                                  /* maximum = 255 */ 
PUT-STRING(SubjPtr,1) = ipSubject.
SET-SIZE(TextPtr) = 16000. 
PUT-STRING(TextPtr,1) = ipBodytext. 
/* --- BUILD ORIGINATOR DETAILS ---------------------*/
SET-SIZE(OriginNamePtr) = LENGTH(ipOrigName) + 1.                           /* maximum = 255 */
PUT-STRING(OriginNamePtr,1) = ipOrigName.                                   /* Originator name */
 
DEFINE VARIABLE OriginDescPtr AS MEMPTR.
SET-SIZE(OriginDescPtr) = 24.
PUT-LONG(OriginDescPtr,1) = 0.                                              /* Reserved */ 
PUT-LONG(OriginDescPtr,5) = 0.                                              /* RecipClass 0 = MAPI_ORIG */ 
PUT-LONG(OriginDescPtr,9) = GET-POINTER-VALUE(OriginNamePtr).               /* Name */
PUT-LONG(OriginDescPtr,13) = 0.                                             /* Address */ 
PUT-LONG(OriginDescPtr,17) = 0.                                             /* EID Size */ 
PUT-LONG(OriginDescPtr,21) = 0.                                             /* Entry ID */
/* ---------- BUILD RECIPIENT DETAILS -------------- */
DO zz = 1 TO intRecips :
    SET-SIZE(RecipNamePtr[zz]) = LENGTH(RecipName[zz]) + 1.                 /* maximum = 255 */ 
    PUT-STRING(RecipNamePtr[zz],1) = RecipName[zz].                         /* Recipient name */
    SET-SIZE(RecipDescPtr[zz]) = 24.
    PUT-LONG(RecipDescPtr[zz],1) = 0.                                       /* Reserved */ 
    PUT-LONG(RecipDescPtr[zz],5) = 1.                                       /* RecipClass 1 = MAPI_TO */ 
    PUT-LONG(RecipDescPtr[zz],9) = GET-POINTER-VALUE(RecipNamePtr[zz]).     /* Name */
    PUT-LONG(RecipDescPtr[zz],13) = 0.                                      /* Address */ 
    PUT-LONG(RecipDescPtr[zz],17) = 0.                                      /* EID Size */ 
    PUT-LONG(RecipDescPtr[zz],21) = 0.                                      /* Entry ID */
END.
/* Populate Memory Indicated By RecipArrayPtr */
SET-SIZE(RecipArrayPtr) = 24 * intRecips.
DO zz = 1 TO intRecips :
    PUT-BYTES(RecipArrayPtr, (zz * 24) - 23)  = GET-BYTES(RecipDescPtr[zz],1,24).
END.
/* ---------- BUILD FILE DETAILS ------------------- */
/* Build File Description Array */
DO zz = 1 TO intAttachs:
    
    SET-SIZE(FilePathNamePtr[zz]) = LENGTH(FilePathName[zz]) + 1.           /* maximum = 255 */
    PUT-STRING(FilePathNamePtr[zz],1) = FilePathName[zz].                   /* File pathname */
 
    FileNam[zz] = SUBSTRING(FilePathName[zz],R-INDEX(FilePathName[zz],"\":U) + 1).
 
    SET-SIZE(FileNamPtr[zz]) = LENGTH(FileNam[zz]) + 1.                     /* maximum = 255 */ 
    PUT-STRING(FileNamPtr[zz],1) = FileNam[zz].                             /* File name */
 
    SET-SIZE(FileDescPtr[zz]) = 24.
    PUT-LONG(FileDescPtr[zz],1) = 0.                                        /* Reserved */ 
    PUT-LONG(FileDescPtr[zz],5) = 0.                                        /* Flags 0 = data file */
    PUT-LONG(FileDescPtr[zz],9) = -1.                                       /* Position */
    PUT-LONG(FileDescPtr[zz],13) = GET-POINTER-VALUE(FilePathNamePtr[zz]).  /* PathName */
    PUT-LONG(FileDescPtr[zz],17) = GET-POINTER-VALUE(FileNamPtr[zz]).       /* File Name */ 
    PUT-LONG(FileDescPtr[zz],21) = 0.                                       /* FileType */
END.
/* Populate Memory Indicated By FileArrayPtr */
SET-SIZE(FileArrayPtr) = 24 * intAttachs.
DO zz = 1 TO intAttachs:
    
    PUT-BYTES(FileArrayPtr, (zz * 24) - 23)  = GET-BYTES(FileDescPtr[zz],1,24).
    
END.
/* ---------- BUILD MESSAGE DETAILS ---------------- */
SET-SIZE(MessageDescPtr) = 48.
PUT-LONG(MessageDescPtr,1) = 0.                                             /* Reserved */
PUT-LONG(MessageDescPtr,5) = GET-POINTER-VALUE(SubjPtr).                    /* Subject */
PUT-LONG(MessageDescPtr,9) = GET-POINTER-VALUE(TextPtr).                    /* Text */
PUT-LONG(MessageDescPtr,13) = 0.                                            /* MessageType */ 
PUT-LONG(MessageDescPtr,17) = 0.                                            /* DateReceived */ 
PUT-LONG(MessageDescPtr,21) = 0.                                            /* ConversationID */ 
PUT-LONG(MessageDescPtr,25) = 1.                                            /* Flags */
PUT-LONG(MessageDescPtr,29) = GET-POINTER-VALUE(OriginDescPtr).             /* Originator */
PUT-LONG(MessageDescPtr,33) = intRecips.                                    /* RecipCount */
PUT-LONG(MessageDescPtr,37) = GET-POINTER-VALUE(RecipArrayPtr).             /* Recips */
PUT-LONG(MessageDescPtr,41) = intAttachs.                                   /* FileCount */
PUT-LONG(MessageDescPtr,45) = GET-POINTER-VALUE(FileArrayPtr).              /* Files */
/* ---------- SEND MESSAGE ------------------------- */
DEFINE VARIABLE ResultInt AS INTEGER NO-UNDO.
RUN MAPISendMail IN hpApi
 (INPUT 0,
  INPUT 0,
  INPUT GET-POINTER-VALUE(MessageDescPtr),
  INPUT 0,                                                                  /* 1 = MAPI_LOGON_UI + 2 = MAPI_NEW_SESSION + 8 = MAPI_DIALOG */
  INPUT 0,     
  OUTPUT ResultInt). 
 
IF ResultInt <> 0 THEN RUN MapiReturnCode.p (INPUT ResultInt).
 
/* ---------- RELEASE RESOURCES -------------------- */
SET-SIZE(SubjPtr) = 0.
SET-SIZE(TextPtr) = 0. 
DO zz = 1 TO intAttachs :
    SET-SIZE(FilePathNamePtr[zz]) = 0.
    SET-SIZE(FileNamPtr[zz])     = 0.
    SET-SIZE(FilePathNamePtr[zz]) = 0.
    SET-SIZE(FileDescPtr[zz])     = 0.
END.
DO zz = 1 TO intRecips :
    SET-SIZE(RecipNamePtr[zz])    = 0.
    SET-SIZE(RecipDescPtr[zz])    = 0.
END.
SET-SIZE(MessageDescPtr) = 0.
SET-SIZE(FileArrayPtr) = 0.
SET-SIZE(RecipArrayPtr) = 0.
SET-SIZE(OriginNamePtr) = 0.
IF VALID-HANDLE(hpAPI) THEN DELETE OBJECT hpAPI.
/* ---------- INTERNAL PROCEDURES ------------------ */
PROCEDURE recips:
/* --------------------------------------------*/
/*    Populate Reciptient Array, RecipName,    */
/*    from comma separated list.               */         
/*---------------------------------------------*/    
    DEFINE VARIABLE xx AS INTEGER NO-UNDO.
    IntRecips = 0.
    DO WHILE ipRecipName <> "":
        xx = INDEX(ipRecipName, ",").
        IF xx > 0 THEN DO:
            intRecips = intRecips + 1.
            RecipName[intRecips] = SUBSTRING(ipRecipName, 1, xx - 1).
            ipRecipName = SUBSTRING(ipRecipName, xx + 1).
        END.
        ELSE DO:
            IF ipRecipName <> "" THEN DO:
                intRecips = intRecips + 1.
                RecipName[intRecips] = ipRecipName.
                ipRecipName = "".
            END.
        END.
    END.
END PROCEDURE.
PROCEDURE attachs:
/* --------------------------------------------*/
/*    Populate Attachment Array, FilePathName  */
/*    from comma separated list.               */         
/*---------------------------------------------*/ 
    DEFINE VARIABLE yy AS INTEGER NO-UNDO.
    IntAttachs = 0.
    DO WHILE ipFilePathName <> "":
        yy = INDEX(ipFilePathName, ",").
        IF yy > 0 THEN DO:
            intAttachs = intAttachs + 1.
            FilePathName[intAttachs] = TRIM(SUBSTRING(ipFilePathName, 1, yy - 1)).
            ipFilePathName = TRIM(SUBSTRING(ipFilePathName, yy + 1)).
        END.
        ELSE DO:
            IF ipFilePathName <> "" THEN DO:
                intAttachs = intAttachs + 1.
                FilePathName[intAttachs] = TRIM(ipFilePathName).
                ipFilePathName = "".
            END.
        END.
    END.
END PROCEDURE.
END PROCEDURE.

Dial a telephone number

The Tapi (Telephony API) can be used to dial a telephone number or pager.
This source is from Johann van der Merwe.
His introduction says:
This is an example of what we use. The code is not cleaned up. We also
use our own dialing properties (for instance a outside line). Hope this
helps. Use MSDN to look up tapiRequestMakeCall for parameter info.

DEFI: DO ON ERROR UNDO, RETURN "ERROR-DEFI":U:
 
  DEFINE INPUT PARAMETER TelNoStr AS CHARACTER NO-UNDO. 
 
  DEFINE VARIABLE GetLine     AS CHARACTER NO-UNDO.
  DEFINE VARIABLE TelNo       AS MEMPTR    NO-UNDO.
  DEFINE VARIABLE i           AS INTEGER   NO-UNDO.
  DEFINE VARIABLE ReturnValue AS INTEGER   NO-UNDO.
END.
 
Main: DO ON ERROR UNDO, RETURN "ERROR-MAIN":U:
 
  GET-KEY-VALUE SECTION "Modem":U KEY "GetLine":U VALUE GetLine.
  IF GetLine = "?":U OR GetLine = ? THEN 
     GetLine = "":U.
 
  SET-SIZE(TelNo) = LENGTH(GetLine + TelNoStr) + 1.
  DO i = 1 TO LENGTH(TelNoStr + GetLine): 
     PUT-BYTE(TelNo,i) = ASC(SUBSTRING(GetLine + TelNoStr,i,1)).
  END.
  PUT-BYTE(TelNo,i) = 0.
  RUN tapiRequestMakeCall (INPUT GET-POINTER-VALUE(TelNo), 
                           INPUT "0":U, 
                           INPUT "0":U, 
                           INPUT "0":U,
                           OUTPUT ReturnValue).
END. 
 
PROCEDURE tapiRequestMakeCall EXTERNAL "tapi32.dll":U:
  DEFINE INPUT  PARAMETER lpszDestAddress AS LONG.
  DEFINE INPUT  PARAMETER lpszAppName     AS CHARACTER.
  DEFINE INPUT  PARAMETER lpszCalledParty AS CHARACTER.
  DEFINE INPUT  PARAMETER lpszComment     AS CHARACTER.
  DEFINE RETURN PARAMETER ReturnValue     AS LONG.
END PROCEDURE.

Interfacing with MAPI (email)

There are different kinds of solutions for using Email from Progress. For example, there are several ActiveX components, there is a Progress 7+8 product with source made by Ketil Parow (you can download a trial version at http:www.sn.no/~ketilp/misc/mapi.zip), you can use the MAPI OLE automation server (there is a document about that on the ActiveX pages on www.dotr.com) or you can use the MAPI through its native API. On this site we'll only discuss the API kind of solutions.
The next sourcecode example was posted by Jeff Ledbetter and was earlier found in Profiles. I ported it to 32-bit.
The example uses the 'Simple MAPI' interface. This interface is not by default available on any machine. The easiest way to ensure if Simple MAPI is available is to check the registry: the "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Messaging Subsystem" variable "MAPI" should have value "1".

 
RUN SendMail ( INPUT "yourself@home.com",
              INPUT "this is the subject line",
              INPUT "This is the body text",
              OUTPUT Okay).
 
 
PROCEDURE SendMail :
DEFINE INPUT PARAMETER send-to-name AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER send-subject AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER send-text    AS CHARACTER NO-UNDO.
DEFINE OUTPUT PARAMETER Okay        AS LOGICAL NO-UNDO INITIAL NO.
 
DEFINE VARIABLE pnames   AS MEMPTR.
DEFINE VARIABLE psendto  AS MEMPTR.
DEFINE VARIABLE psubj    AS MEMPTR.
DEFINE VARIABLE ptext    AS MEMPTR.
DEFINE VARIABLE pmessage AS MEMPTR.
 
DEFINE VARIABLE wans AS INTEGER .
 
SET-SIZE(pnames)  = 24.
SET-SIZE(psendto) = 16.
 
 
PUT-LONG(pnames,1)  = 0. /* Reserved */
PUT-LONG(pnames,5)  = 1. /* Recip Class MAPI_TO */
PUT-LONG(pnames,9)  = GET-POINTER-VALUE(psendto). /* Names */
PUT-LONG(pnames,17) = 0. /* EID Size */
 
SET-SIZE(psubj)    = 100.
SET-SIZE(ptext)    = 8000.
SET-SIZE(pmessage) = 48.
 
PUT-STRING(psubj,1)   = send-subject.
PUT-STRING(ptext,1)   = send-text.
PUT-STRING(psendto,1) = send-to-name.
 
PUT-LONG(pmessage,1)  = 0. /* Reserved */
PUT-LONG(pmessage,5)  = GET-POINTER-VALUE(psubj). /* Subject */
PUT-LONG(pmessage,9)  = GET-POINTER-VALUE(ptext). /* Text */
PUT-LONG(pmessage,25) = 0. /* Flags */
PUT-LONG(pmessage,33) = 1. /* RecipCount */
PUT-LONG(pmessage,37) = GET-POINTER-VALUE(pnames).
PUT-LONG(pmessage,41) = 0.
 
RUN MAPISendMail IN hpApi(INPUT 0,      /* mapi session handle */
                          INPUT 0,      /* parent window handle */
                          INPUT GET-POINTER-VALUE(pmessage),
                          INPUT 0,      /* flags */
                          INPUT 0,      /* reserved, must be 0 */
                          OUTPUT Wans). /* error status */
IF Wans<>0 THEN
   MESSAGE "Mail not sent, error code=" Wans
           VIEW-AS ALERT-BOX.
ELSE
   Okay = YES.
 
/* dealloc memory */
SET-SIZE(pnames)   = 0.
SET-SIZE(psendto)  = 0.
SET-SIZE(psubj)    = 0.
SET-SIZE(ptext)    = 0.
SET-SIZE(pmessage) = 0.
 
END PROCEDURE.

Comments on MAPISendMail

The first parameter is a Mapi-session handle. If 0, MAPI will try to find a shared session or create a temporary session for the duration of the call and it might have to show a login dialog. So if you need to send several mails it might be better to create a session up front and reuse its handle.
The second parameter is a parent window handle. If MapiSendMail has to show a dialog (for example a login dialog), it will be an application-modal dialog parented to this window handle.The value 0 is valid but will not block input in your Progress application.
The third parameter is a fairly complicated message structure. This example only creates a simple mail but MAPI also allows to add one or more attachements as shown in the source on the next page ([[mapiattachment]] wikilink).
If you do not specify a recipient (send-to-name) you must allow MAPI to ask for one. That is, you must use the MAPI_DIALOG (=8) flag in the 4th parameter of MapiSendMail.


MAPI return codes

By Johann van der Merwe.

 
PROCEDURE MapiReturnCode  :
 
INPUT PARAMETER ResultInt AS INTEGER. /* result from MAPISendMail */
DEFINE VARIABLE RESULT AS CHARACTER NO-UNDO.
 
IF ResultInt <> 0 THEN DO:  /* 0 = Success */ 
   CASE ResultInt:
     WHEN  1 THEN RESULT = "User Abort".
     WHEN  2 THEN RESULT = "Failure".
     WHEN  3 THEN RESULT = "Login Failure".
     WHEN  4 THEN RESULT = "Disk Full".
     WHEN  5 THEN RESULT = "Insufficient Memory".
     WHEN  6 THEN RESULT = "Blk Too Small".
     WHEN  8 THEN RESULT = "Too Many Sessions".
     WHEN  9 THEN RESULT = "Too Many Files".
     WHEN 10 THEN RESULT = "Too Many Recipients".
     WHEN 11 THEN RESULT = "Attachment Not Found".
     WHEN 12 THEN RESULT = "Attachment Open Failure".
     WHEN 13 THEN RESULT = "Attachment Write Failure".
     WHEN 14 THEN RESULT = "Unknown Recipient".
     WHEN 15 THEN RESULT = "Bad Recipient type".
     WHEN 16 THEN RESULT = "No Messages".
     WHEN 17 THEN RESULT = "Invalid Message".
     WHEN 18 THEN RESULT = "Bodytext Too Large".
     WHEN 19 THEN RESULT = "Invalid Session".
     WHEN 20 THEN RESULT = "Type Not Supported".
     WHEN 21 THEN RESULT = "Ambiguous Recipient".
     WHEN 22 THEN RESULT = "Message in use".
     WHEN 23 THEN RESULT = "Network failure".
     WHEN 24 THEN RESULT = "Invalid edit fields".
     WHEN 25 THEN RESULT = "Invalid recipients".
     WHEN 26 THEN RESULT = "Feature not supported"
     OTHERWISE RESULT    = "Unknown error".
   END CASE.
 
   DO ON ENDKEY UNDO, LEAVE:
      MESSAGE ResultInt RESULT
              VIEW-AS ALERT-BOX.
   END.
END.

smtpmail.p

Since this is a chapter about email, it should be noted there is an excellent program named smtpmail.p available for free at [broken link removed]

This program is entirely written in regular Progress ABL without any WIN32 API call.


Using Microsoft CDO to send e-mail

You can use Microsoft's CDO object library to easily send emails from Progress using ActiveX.
It seems to use the local SMTP server installed with IIS, so you can get started with very little code.

def var objMessage as com-handle.

create "CDO.Message" objMessage.

objMessage:Subject = "Example CDO Message from Progress".
objMessage:From = "example@example.com".
objMessage:To = "example@example.com".
objMessage:TextBody = "This is some sample message text.".
objMessage:Send().

More extensive examples of using CDO (with VBScript) can be found here:
http://www.paulsadowski.com/WSH/cdo.htm
http://www.lewisroberts.com/2006/06/09/sending-cdomessage-with-importanc...


Using Outlook to send e-mail

There are many ways to send email, smtpmail.p from freeframework.org is known to be very good.
In the past there have been many quesions about Outlook. Here is one code snippet, seen on Peg in an email from John Lubenow (I hope we have permission to use this, if not just delete this topic and let me know please)

/** Send Outlook Mail **/
DEFINE INPUT PARAMETER mailto AS CHARACTER FORMAT "x(30)".
DEFINE INPUT PARAMETER mailcc AS CHARACTER FORMAT "x(30)".
DEFINE INPUT PARAMETER subject AS CHARACTER FORMAT "x(50)".
DEFINE INPUT PARAMETER body AS CHARACTER FORMAT "x(255)".

    DEFINE VARIABLE chOutlook AS COM-HANDLE NO-UNDO.
    DEFINE VARIABLE chmail AS COM-HANDLE NO-UNDO.

    CREATE "outlook.application.9" choutlook NO-ERROR.
    ASSIGN chmail = chOutlook:createItem(0).

    /** Assign data **/
    ASSIGN chmail:Subject  = subject.
    ASSIGN chMail:Body = body.
    ASSIGN chMail:TO = mailto.
    ASSIGN chMail:CC = mailcc.

    /** example for one attachment: **/
    chMail:Attachments:Add( [insert-file-name-here] ) NO-ERROR.
    chMail:Attachments(1):DisplayName =  [insert-file-display-name-here].

    /** view mail **/
    chMail:Display(1).
    chMail:SEND().
   
    RELEASE OBJECT chmail.
    RELEASE OBJECT choutlook.