Sending E-Mail from within SAS Software

Overview of SAS Support for E-Mail

SAS software enables you to send e-mail by way of a DATA step, SAS procedure, or SCL. Specifically, you can
  • use the logic of the DATA step or SCL to subset e-mail distribution based on a large data set of e-mail addresses.
  • send e-mail automatically upon completion of a SAS program that you submitted for batch processing.
  • direct output through e-mail that is based on the results of processing.
SAS e-mail is implemented in the following language elements:
  • the EMAILHOST= and EMAILPORT= SAS options. SAS software sends all e-mail over a socket to an SMTP server. You or your system administrator might have to specify the EMAILHOST= system option to identify the host that runs an SMTP server on your network. The EMAILHOST= option defaults to localhost.The EMAILPORT= system option identifies the port number on the SMTP server for e-mail access. The default port number is 25. For more information about SMTP, see “The SMTP E-Mail Interface” in SAS Language Reference: Concepts.
  • the FILE and FILENAME statements, which are used to specify the name of an e-mail fileref and the mailing instructions that are used to send it. For more information, see “FILENAME Statement, EMAIL (SMTP) Access Method” in the SAS Statements: Reference . Options that you specify in the FILE statement override any corresponding options that you specified in the FILENAME statement.
  • the PUT statement, which is used in the DATA step or SCL to create the e-mail message and to specify or change mailing directives. For more information, see “PUT Statement Syntax for E-Mail” below.

PUT Statement Syntax for E-Mail

In your DATA step, after using the FILE statement to define your e-mail fileref as the output destination, use PUT statements to define the body of the message.
You can also use PUT statements to specify e-mail directives that override the attributes of your electronic mail message (TO, CC, SUBJECT, TYPE, ATTACH) or perform actions with it (such as SEND, ABORT, and start a NEWMSG). Specify only one directive in each PUT statement; each PUT statement can contain only the text associated with the directive that it specifies. Use quotation marks as necessary to construct the arguments of the PUT statement. However, the final string written by the PUT statement does not need to be enclosed in quotation marks.
The directives that change the attributes of a message are
!EM_TO! addresses
replaces the current primary recipient addresses with addresses. For example:
PUT "!EM_TO!" "joe@somplace.org";
or
user="joe@somplace.org"; put '!EM_TO!' user;
To specify more than one address, enclose the list of addresses in parentheses and each address in single or double quotation marks, and separate each address with a space:
PUT "!EM_TO!" ('joe@smplc.org' 'jane@diffplc.org');
or
list=('joe@smplc.org' 'jane@diffplc.org'); put '!EM_TO!' list;
To specify a name with the address, enclose the address in angle brackets, as follows:
PUT "!EM_TO!" "Joe Smith <joe@somplace.org>";
or
user="Joe Smith <joe@somplace.org>"; put '!EM_TO!' user;
!EM_CC! addresses
replaces the current copied recipient addresses with addresses. For example:
PUT "!EM_CC!" "joe@somplace.org";
or
user="joe@somplace.org"; put '!EM_CC!' user;
To specify more than one address, enclose the list of addresses in parentheses and each address in single or double quotation marks, and separate addresses with a space:
PUT "!EM_CC!" ('joe@smplc.org' 'jane@diffplc.org');
or
list=('joe@smplc.org' 'jane@diffplc.org'); put '!EM_CC!' list;
To specify a name with the address, enclose the address in angle brackets, as follows:
PUT "!EM_CC!" "Joe Smith <joe@somplace.org>";
or
user="Joe Smith <joe@somplace.org>"; put '!EM_CC!' user;
!EM_BCC! addresses
replaces the current blind copied recipient addresses with addresses. For example:
PUT "!EM_BCC!" "joe@somplace.org";
or
user="joe@somplace.org"; put '!EM_BCC!' user;
To specify more than one address, enclose the list of addresses in parentheses and each address in single or double quotation marks, and separate addresses with a space:
PUT "!EM_BCC!" ('joe@smplc.org' 'jane@diffplc.org');
or
list=('joe@smplc.org' 'jane@diffplc.org'); put '!EM_BCC!' list;
To specify a name with the address, enclose the address in angle brackets, as follows:
PUT "!EM_BCC!" "Joe Smith <joe@somplace.org>";
or
user="Joe Smith <joe@somplace.org>"; put '!EM_BCC!' user;
!EM_FROM! 'address'
replaces the current address of the sender of the message with address. For example:
PUT "!EM_FROM! "john@hisplace.org"
or
user="john@hisplace.org"; put '!EM_FROM!' user;
!EM_SUBJECT! subject
replaces the current subject of the message with subject.
!EM_CONTENTTYPE! content-type
replaces the current content type of the message with content-type.
!EM_ATTACH! “file-specification
replaces the current list of attachments with file-specification. Enclose the file-specification in double quotation marks.
To attach more than one file or a file with additional attachment options, enclose the list of file specifications or options in parentheses and separate each file-specification with a space. The attachment options are
CONTENT_TYPE='content/type'
specifies the MIME content type that should be associated with this attachment. The default content type is text/plain. CONTENT_TYPE= can be specified as:
  • CONTENT_TYPE=
  • CONTENT-TYPE=
  • TYPE=
  • CT=
EXTENSION='extension'
specifies the filename extension on the recipient's file that is attached. This extension is used by the recipient's e-mail system for selecting the appropriate utility to use for displaying the attachment. The default attachment extension is "txt". EXTENSION= can be specified as EXT=.
NAME='name'
specifies a different name to be used for the attachment.
The following examples show the syntax for specifying attachment options in a PUT statement:
put '!EM_ATTACH!' "('user.misc.pds(member)' content_type='text/html'                   extension='html')";  put '!EM_ATTACH!' "('user.misc.jcl(sasjcl)' extension='doc',                  'userid.sas.output' content_type='image/gif' extension='gif'                  name='Test Results')";  mycfg="'user.misc.jcl(sasjcl)'"; syscfg="'user.sas.output' content_type='image/gif' ext='gif'"; put '!EM_ATTACH!' "("mycfg","syscfg")";
These directives perform actions:
!EM_SEND!
sends the message with the current attributes. By default, SAS sends a message when the fileref is closed. The fileref closes when the next FILE statement is encountered or the DATA step ends. If you use this directive, SAS software sends the message when it encounters the directive and again at the end of the DATA step.
!EM_ABORT!
stops the current message. You can use this directive to stop SAS software from automatically sending the message at the end of the DATA step.
!EM_NEWMSG!
clears all attributes of the current message, including TO, CC, SUBJECT, TYPE, ATTACH, and the message body.

Example: Sending E-Mail from the DATA Step

Suppose you want to share a copy of your SASV9 CONFIG file with your coworker Jim, whose user ID is JBrown. You could send it by submitting the following DATA step:
filename mymail email 'JBrown@ajax.com'
         subject='My SASV9 CONFIG file'
         attach="jbrown.tso.config(sasV9)";

data _null_;
  file mymail;
  put 'Jim,';
  put 'This is my SASV9 CONFIG file.';
  put 'I think you might like the new options I added.';
run;
The following example sends a message and two attached files to multiple recipients. It specifies the e-mail options in the FILE statement instead of in the FILENAME statement:
filename outbox email 'ron@acme.com';

data _null_;
  file outbox
     to=('ron@acme.com' 'lisa@acme.com')
     /* Overrides value in */
     /* filename statement */

     cc=('margaret@yourcomp.com'
         'lenny@laverne.abc.com')
     subject='My SAS output'
     attach=("my.sas.output" "my.sas.code")
     ;
  put 'Folks,';
  put 'Attached is my output from the
      SAS program I ran last night.';
  put 'It worked great!';
run;
You can use conditional logic in the DATA step to send multiple messages and to control which recipients receive which message. For example, suppose you want to send customized reports to members of two different departments. Here is a DATA step example:
filename reports email 'Jim@corp.com';

data _null_;
  file reports;
  infile cards eof=lastobs;
  length name dept $ 21;
  input name dept;
  put '!EM_TO!' name;
   /* Assign the TO attribute      */

  put '!EM_SUBJECT! Report for ' dept;
   /* Assign the SUBJECT attribute */

  put name ',';
  put 'Here is the latest report for ' dept '.';
  if dept='marketing' then
    put '!EM_ATTACH!' "userid.market.report";
  else
    /* ATTACH the appropriate report */

    put '!EM_ATTACH!' "userid.devlpmnt.report";
  put '!EM_SEND!';
    /* Send the message */

  put '!EM_NEWMSG!';
    /* Clear the message attributes */

  return;
lastobs: put '!EM_ABORT!';
    /* Abort the message before the */
    /*   RUN statement causes it to */
    /*   be sent again.             */

  datalines;
Susan          marketing
Jim            marketing
Rita           development
Herb           development
;
run;
The resulting e-mail message and its attachments are dependent on the department to which the recipient belongs.
Note: You must use the !EM_NEWMSG! directive to clear the message attributes between recipients. The !EM_ABORT! directive prevents the message from being automatically sent at the end of the DATA step.

Sending Procedure Output as E-Mail

Overview of Sending Procedure Output as E-Mail

E-mail can be used to send procedure output. ODS HTML procedure output must be sent with the RECORD_SEPARATOR (RS) option set to NONE. For z/OS, ODS produces an HTML stream with embedded record-separator characters, by default. When the RS option is set to NONE, ODS writes one line of HTML at a time to the file. Make sure that the file's record length is large enough to accommodate the longest HTML line.
The following section contains examples that illustrate how to send ODS HTML and graph output in the body of an e-mail message and also as attachments to e-mail.

Examples: Sending Procedure Output via E-Mail

The following example shows how to use ODS to send HTML output in e-mail:
filename outbox email
        to='susan@mvs'
        type='text/html'
        subject='Temperature conversions'
        ;

data temperatures;
   do centigrade = -40 to 100 by 10;
      fahrenheit = centigrade*9/5+32;
      output;
   end;
run;

ods html
  body=outbox /* Mail it! */
  rs=none;

  title 'Centigrade to Fahrenheit conversion table';
proc print;
  id  centigrade;
  var fahrenheit;
run;

ods html close;
The following example shows how to create and send a GIF image in an e-mail message:
filename gsasfile email
        to='Jim@acme.com'
        type='image/gif'
        subject="SAS/GRAPH output."
        ;

goptions dev=gif gsfname=gsasfile;

proc gtestit pic=1; run;
The following example shows how to create ODS HTML and send it as attachments to an e-mail message:
 /* ---------------------------------------- */
 /* allocate PDSE to contain the HTML output */
 /* ---------------------------------------- */
filename odsout '.mvsmail1.pdse' disp=(new,catlg,delete)
                dsorg=po dsntype=library;

 /* ------------------------------------ */
 /* stop sending output to OUTPUT window */
 /* ------------------------------------ */
ods listing close;

 /* ----------------------------------------------------- */
 /* Assign frame, contents and body files.                */
 /* Specify the URLs to have the .html extension.         */
 /* Specify the PATH to be the PDSE.                      */
 /* Specify RS=NONE to write one line of HTML per record. */
 /* This is necessary when e-mailing the HTML output.    */
 /* ----------------------------------------------------- */
ods html frame='shoes1f'
    contents='shoes1c' (url='shoes1c.html')
    body='shoes1b'     (url='shoes1b.html')
    path=odsout
    rs=none;

data newshoes;
   set sashelp.shoes;
   where Region in ('Canada' 'Central America/Caribbean'
                    'South America' 'United States');
run;

 /* ----------------------------------------- */
 /* sort the data set and generate the report */
 /* ----------------------------------------- */
proc sort data=newshoes;
   by Region Subsidiary Product;
run;

options nobyline;
title1 'Sales for Regions #byval(Region)';
proc report data=newshoes nowindows;
  by Region;
  column Region Product Subsidiary Sales;
  define Region / noprint group;
  define Product    / display group;
  define Subsidiary / display group;
  define Sales   / display sum format=dollar8.;
  compute after Region;
          Product='Total';
  endcomp;
  break after Region    / summarize style=rowheader;
run;

 /* ------------------------------------------------------ */
 /* Close the HTML destination and open the listing output */
 /* ------------------------------------------------------ */
ods html close;
ods listing;

 /* ----------------- */
 /* E-mail the report */
 /* ----------------- */
filename email email 'fred@bedrock.com'
     subject="Shoe report 1"
     type="text/plain"
attach=(".mvsmail1.pdse(shoes1f)" content_type='text/html' extension='html'
        ".mvsmail1.pdse(shoes1c)" content_type='text/html' extension='html'
        ".mvsmail1.pdse(shoes1b)" content_type='text/html' extension='html') ;
data _null_;
   file email;
   put 'Here is the latest Shoe sales report';
run;
The following example shows how to create ODS HTML and GIF files and send them as e-mail attachments:
 /* ------------------------------------------------ */
 /* Define the UNIX System Services USS directory to */
 /* contain the graphics and HTML output.            */
 /* ------------------------------------------------ */
filename odsout '/u/myhome/public_html';

 /* ------------------------------------------------ */
 /* stops sending output to GRAPH and OUTPUT windows */
 /* ------------------------------------------------ */
ods listing close;

 /* ---------------------------- */
 /* set the graphics environment */
 /* ---------------------------- */
goptions reset=global gunit=pct
         colors=(black blue green red)
         hsize=8.42 in vsize=6.31 in ftitle=zapfb
         ftext=swiss htitle=4 htext=2.5
         device=gif transparency noborder;

 /* --------------------------------- */
 /* add the HTML variable to NEWSHOES */
 /* --------------------------------- */
data newshoes;
   set sashelp.shoes;
   where Region in ('Canada' 'Central America/Caribbean'
                    'South America' 'United States');
   length regdrill $40;

if Region='Canada' then
   regdrill='HREF="shoes1_regsales.html#IDX1"';

else if Region='Central America/Caribbean' then
   regdrill='HREF="shoes1_regsales.html#IDX2"';

else if Region='South America' then
   regdrill='HREF="shoes1_regsales.html#IDX3"';

else if Region='United States' then
   regdrill='HREF="shoes1_regsales.html#IDX4"';

run;

 /* ------------------------------------------------------*/
 /* Assign the destination for the ODS graphics output    */
 /* and ODS HTML files.                                   */
 /* Specify RS=NONE to write one line of HTML per record. */
 /* This is necessary when e-mailing the HTML output.     */
 /* ----------------------------------------------------- */
ods html path=odsout
         body='shoe_report.html'
         rs=none
         nogtitle;

 /* ----------------------------------- */
 /* define title and footnote for chart */
 /* ----------------------------------- */
title1 'Total Sales for the Americas';
footnote1 h=3 j=l 'click on bars' j=r 'REPORT3D ';

 /* ----------------------------------- */
 /* assign a pattern color for all bars */
 /* ----------------------------------- */
pattern color=cyan;

 /* --------------------------- */
 /* define axis characteristics */
 /* --------------------------- */
axis1 order=(0 to 7000000 by 1000000)
      minor=(number=1)
      label=none;
axis2 label=none offset=(4,4)
      value=('Canada' 'C. Amr./Car.'
             'S. America' 'USA');

 /* --------------------------- */
 /* generate vertical bar chart */
 /* --------------------------- */
proc gchart data=newshoes;
   vbar3d Region / discrete
                 width=6
                 sumvar=sales
                 html=regdrill
                 coutline=black
                 cframe=blue
                 maxis=axis2
                 raxis=axis1
                 name='shoes1 ';
run;
quit;

 /* ----------------------------------------------------- */
 /* Open the HTML destination for the PROC PRINT output.  */
 /* Specify RS=NONE to write one line of HTML per record. */
 /* This is necessary when e-mailing the HTML output.     */
 /* ----------------------------------------------------- */
ods html body='shoes1_regsales.html'
         rs=none
         path=odsout;

 /* ----------------------------------------- */
 /* sort data set NEWSHOES in order by region */
 /* ----------------------------------------- */
proc sort data=newshoes;
   by Region Subsidiary Product;
run;
quit;

 /* -------------------------------------------- */
 /* print a report of shoe sales for each Region */
 /* -------------------------------------------- */
goptions reset=footnote;
option nobyline;
title 'Sales Report for #byval(Region)';
proc report data=newshoes nowindows;
  by Region;
  column Region Subsidiary Product Sales;
  define Region    / noprint group;
  define Subsidiary    / display group;
  define Product / display group;
  define Sales   / display sum format=dollar12.;
  compute after Region;
          Subsidiary='Total';
  endcomp;
  break after Region / summarize style=rowheader page;
run;

 /* ------------------------------------------------------ */
 /* Close the HTML destination and open the listing output */
 /* ------------------------------------------------------ */
ods html close;
ods listing;

 /* ---------------- */
 /* Email the report */
 /* -----------------*/
filename email email 'barney@bedrock.com'
     subject="Shoe report 2"
     type="text/plain"
attach=("./public_html/shoe_report.html" content_type='text/html'
        "./public_html/shoes1_regsales.html" content_type='text/html'
        "./public_html/shoes1.gif" content_type='image/gif') ;
data _null_;
   file email;
   put 'Here is the latest Shoe sales report';
run;

Example: Directing Output as an E-Mail Attachment with Universal Printing

Follow these steps to send procedure output as an attachment to an e-mail message.
  1. Define a Universal printer with a device type of 'EMAIL'.
  2. Establish a printing destination with the PRINTERPATH= option:
    options printerpath='emailjoe';
    The OPTIONS statement assigns EMAILJOE as the default Universal printer. EMAILJOE remains the default printer for the duration of the SAS session, unless it is overridden by another OPTIONS statement.
  3. Identify the print destination to SAS:
    ods printer;
    The ODS PRINTER statement enables procedure output to be formatted for a high-resolution printer. Because the ODS PRINTER statement does not specify a filename or fileref, ODS output is sent to the Universal Printing default printer (EMAILJOE).
  4. Issue a print command or procedure:
    proc print data=sashelp.shoes;
      where region="Canada";
      run;
    PROC PRINT generates procedure output in standard ODS format. The output is sent to the attachment file associated with EMAILJOE.
  5. Remove the print destination:
    ods printer close;
    The second ODS PRINTER statement removes the ODS print destination. The procedure output is sent to EMAILJOE, which sends the e-mail message with the attached file to the e-mail recipient.
The following program defines a registry entry for printing procedure output to an e-mail attachment:
/* STEP 1 */
data printers;
  name = 'emailjoe';
  protocol = 'Ascii';
  trantab = 'GTABCMS';
  model = 'PostScript Level 1 (Gray Scale)';
  device = 'EMAIL';
  dest = 'John.Doe@sas.com';
  hostopt = "recfm=vb ct='application/PostScript'
    subject='Canada Report' ";
  run;

/* STEP 2 */
proc prtdef data=printers replace list;
run;

Example: Sending E-Mail by Using SCL Code

The following example is the SCL code that underlies a frame entry design for e-mail. The frame entry includes these text-entry fields:
mailto
the user ID of the e-mail recipient
copyto
the user ID of the recipient of the e-mail copy (CC)
attach
the name of the file to attach
subject
the subject of the e-mail message
line1
the text of the e-mail message
The frame entry also contains a push button named SEND that causes this SCL code (marked by the send: label) to execute.
send:

   /* set up a fileref */

   rc = filename('mailit','userid','email');

   /* if the fileref was successfully set up
      open the file to write to */

   if rc = 0 then do;
      fid = fopen('mailit','o');
      if fid > 0 then do;

         /* fput statements are used to
            implement writing the
            mail and the components such as
            subject, who to mail to, etc. */


         fputrc1  = fput(fid,line1);
         rc = fwrite(fid);

         fputrc2  = fput(fid,'!EM_TO! '||mailto);
         rc = fwrite(fid);
         fputrc3  = fput(fid,'!EM_CC! '||copyto);
         rc = fwrite(fid);

         fputrc4  = fput(fid,'!EM_ATTACH! '||attach);
         rc = fwrite(fid);
         fputrc5  = fput(fid,'!EM_SUBJECT! '||subject);
         rc = fwrite(fid);

         closerc  = fclose(fid);
      end;
   end;
return;

cancel:
   call execcmd('end');
return;