Close

Sending Email with Oracle, Part 1: UTL_MAIL

Sending Email with Oracle

UTL_MAIL

The UTL_MAIL package is an interesting addition to the database functionality because it came after UTL_SMTP and could have been added to the existing functionality, but was instead split off into its own package. The package is not installed by default either. If you wish to use UTL_MAIL, your DBA will need to run the following two scripts:

$ORACLE_HOME/rdbms/admin/utlmail.sql
$ORACLE_HOME/rdbms/admin/prvtmail.plb

You will also need to set the SMTP_OUT_SERVER system parameter to a comma-delimited list of at least one SMTP host, and optionally ports if not using the default port of 25. If SMTP_OUT_SERVER is not set (i.e. NULL,) the package is supposed to default to the DB_DOMAIN parameter, however most, if not all, versions (up through at least 21.3) have a bug in them preventing the db_domain defaulting from working. If you are using an old version of the database (11gR1 or earlier,) the SMTP_OUT_SERVER parameter is not session or system modifiable. You DBA will need to set the parameter and then restart the instance to apply the change.

And last, the DBA will then need to grant the EXECUTE privilege on the package to users either directly or through a role.

Strangely, and erroneously, comments within the script for the package specification mention the following two parameters which do not exist and, thankfully, are not referenced by the package.

** SMTP_SERVER=my_server.my_company.com
** SMTP_DOMAIN=my_company.com

These comment errors also exist up through at least version 21.3.

The package has had only a few changes since its 10.1 introduction. Version 11.1 changed the package to use INVOKER Rights. Version 11.2 introduced the REPLYTO parameter to each procedure.

There are three procedures in the package, all following a similar API.

  • UTL_MAIL.SEND – sends a single text message of up to 32K (the varchar2 limit)
  • UTL_MAIL.SEND_ATTACH_RAW – sends a single text message up to 32K with the option to include a RAW attachment of up to 32K bytes.
  • UTL_MAIL.SEND_ATTACH_VARCHAR2 sends a single text message up to 32K with the option to include a text attachment of up to 32K.

Most of the parameters are the same for all three procedures. The highlighted rows below, as their names imply, only apply to the procedures that send an attachment.

sender Email address of the sender
recipients Email addresses of the recipient(s), separated by commas
cc Email addresses of the CC recipient(s), separated by commas, default is NULL
bcc Email addresses of the BCC recipient(s), separated by commas, default is NULL
subject String to be included as email subject string, default is NULL
message Text message body
mime_type Mime type of the message, default is ‘text/plain; charset=us-ascii’
priority Message priority, which maps to the X-priority field. 1 is the highest priority and 5 the lowest. The default is 3.
attachment RAW or VARCHAR2 attachment
att_inline Specifies whether the attachment is viewable inline with the message body, default is TRUE
att_mime_type Mime type of the attachment, default is ‘application/octet’ for RAW or ‘text/plain; charset=us-ascii’ for VARCHAR2
att_filename String specifying a filename containing the attachment, default is NULL
replyto Defines to whom the reply email is to be sent

Once the installation, parameters, and grants are all set up, the usage is quite simple.

BEGIN
   UTL_MAIL.send(
      sender      => 'sean.stuber@gmail.com',
      recipients  => 'john.doe@example.com,jane.doe@example.com',
      subject     => 'Test Subject',
      message     => 'Hello World!'
   );
 END;

Sending an attachment isn’t much harder. In the example below I’m pulling the source code of one of my functions into a single varchar2 variable and emailing it to a couple of recipients.

DECLARE
   -- UTL_MAIL will allow attachments up to 32K
   v_text   VARCHAR2(32767);
BEGIN
   -- Read the source code of one of my functions into a variable
   -- I know this function will fit within 32K
   FOR s IN (SELECT text
               FROM user_source
              WHERE name = 'SPLIT_CLOB'
                AND type = 'FUNCTION'
              ORDER BY line)
   LOOP
      v_text := v_text || s.text;
   END LOOP;

   UTL_MAIL.send_attach_varchar2(
      sender     => 'sean.stuber@gmail.com',
      recipients => 'john.doe@example.com,jane.doe@example.com',
      subject    => 'Split Clob source attached',
      message    => 'I hope you find the attached file helpful.',
      attachment => v_text,
      att_inline => FALSE,
      att_filename => 'split_clob_function.txt'
   );
END;

To send a RAW file the general structure is the same as sending text. Gather your RAW content into a variable and then attach the variable. In this example I’m pulling a small image file (JPEG format) from a table and attaching it to my email message.

DECLARE
    -- UTL_MAIL will allow attachments up to 32K
    v_image   RAW(32767);
BEGIN
    -- Read the image file into variable
    FOR s IN (SELECT rawimage
                FROM my_images
               WHERE id=1)
    LOOP
       v_text := v_text || s.text;
    END LOOP;
    UTL_MAIL.send_attach_raw(
       sender     => 'sean.stuber@gmail.com',
       recipients => 'john.doe@example.com,jane.doe@example.com',
       subject    => 'sample image attached',
       message    => 'Attached is a simple stick figure.',
       attachment => v_image,
       att_inline => FALSE,
       att_filename => 'sample.jpg'
    );
END;

In both of the attachment examples I chose to render the attachment as a file. If instead I wanted the content to be embedded within the body of the email it would just be a matter of changing the att_inline parameter to TRUE. This will generally work ok for text inlining but for images or other RAW types, the final rendering will be dependent on the client software receiving the email.

Using other mime types such as ‘text/html’ will allow you to send formatted text but the message will be more complicated as you must construct valid html content so the client can render it and the formatting will be subject to the level of html support in the recipient’s client software.

The cc, bcc, and replyto parameters work as you would expect them to in standard email clients.

That’s pretty much all there is to UTL_MAIL. Its simplicity is its appeal; but that simplicity comes with some fairly obvious restrictions. Your message must be less than or equal to 32K in length. Your attachments can’t be larger than 32K either. You are also limited to only one attachment per email. The smtp servers used can not require authentication.

For these reasons, I generally prefer to use UTL_SMTP. Even though it requires additional work, UTL_SMTP is still not that hard, and you can always write a wrapping procedure to hide the complexity. In fact, if you look at ALL_DEPENDENCIES you can see UTL_MAIL uses UTL_SMTP, so it is just a wrapper anyway and you can build one yourself to suit your needs.