首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

Oracle UTL_SMTP 發送郵件完整實作:支援中文、附件、SSL/TLS 驗證

     編輯:Oracle 資料庫相關知識

前言

Oracle 內建 UTL_SMTP 套件可直接在 PL/SQL 中發送郵件,搭配 UTL_ENCODE 處理 Base64 認證與 UTL_RAW 處理編碼轉換,即可實作支援中文主旨/內容、SMTP AUTH 驗證的郵件發送功能。

核心程序完整碼

create or replace procedure send_mail_(
  p_from      varchar2,  -- 寄件人信箱
  p_fromuser  varchar2,  -- 寄件人顯示名稱
  p_touser    varchar2,  -- 收件人顯示名稱
  p_to        varchar2,  -- 收件人信箱(多筆用 ; 分隔)
  p_cc        varchar2,  -- 副本信箱
  p_subject   varchar2,  -- 主旨
  p_message   varchar2,  -- 內容(支援 HTML)
  p_user      varchar2,  -- SMTP 帳號
  p_mailhost  varchar2,  -- SMTP 主機
  p_psd       varchar2   -- SMTP 密碼
) is
  v_conn      utl_smtp.connection;
  v_msg       varchar2(32700);
  v_touser1   varchar2(4000);
  v_to        varchar2(500);
  v_touser    varchar2(500);
  psrc        varchar2(4000);
  psrc1       varchar2(4000);
  i number := 1; j number := 1; m number := 1; n number := 1;
  str_error   varchar2(20000);
begin
  -- 1. 建立連線
  v_conn := utl_smtp.open_connection(p_mailhost, 25);
  utl_smtp.ehlo(v_conn, p_mailhost);  -- 必須用 EHLO 支援 AUTH

  -- 2. SMTP AUTH LOGIN
  utl_smtp.command(v_conn, 'AUTH LOGIN');
  utl_smtp.command(v_conn, utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(p_user))));
  utl_smtp.command(v_conn, utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(p_psd))));

  -- 3. 寄件人
  utl_smtp.mail(v_conn, '<' || p_from || '>');

  -- 4. 收件人(支援多筆 ; 分隔)
  psrc  := rtrim(ltrim(p_to, ';'), ';') || ';';
  psrc1 := rtrim(ltrim(p_touser, ';'), ';') || ';';
  if nvl(instr(psrc, ';', j), 0) > 0 then
    loop
      i := nvl(instr(psrc, ';', j), 0);
      m := nvl(instr(psrc1, ';', n), 0);
      if i > 0 then
        v_to := trim(substr(psrc, j, i - j));
        v_touser := nvl(trim(substr(psrc1, n, m - n)), '1');
        utl_smtp.rcpt(v_conn, v_to);
        if v_touser = '1' then
          v_touser := trim(substr(v_to, 1, instr(v_to, '@') - 1));
        end if;
        if j = 1 then
          v_touser1 := v_touser1 || v_touser || '<' || v_to || '>';
        else
          v_touser1 := v_touser1 || ';' || v_touser || '<' || v_to || '>';
        end if;
        j := i + 1; n := m + 1;
      end if;
      exit when i = 0;
    end loop;
  else
    utl_smtp.rcpt(v_conn, p_to);
    v_touser1 := v_touser1 || p_touser || '<' || p_to || '>';
  end if;

  -- 5. 副本(CC)
  i := 1; j := 1;
  if nvl(p_cc, 'aa') <> 'aa' then
    psrc := rtrim(ltrim(p_cc, ';'), ';') || ';';
    if nvl(instr(psrc, ';', j), 0) > 0 then
      loop
        i := nvl(instr(psrc, ';', j), 0);
        if i > 0 then
          v_to := trim(substr(psrc, j, i - j));
          j := i + 1;
          utl_smtp.rcpt(v_conn, v_to);
        end if;
        exit when i = 0;
      end loop;
    elsif nvl(p_cc, '1') <> '1' then
      utl_smtp.rcpt(v_conn, p_cc);
    end if;
  end if;

  -- 6. 組裝郵件內容(Header + Body)
  v_msg := 'Date: ' || to_char(sysdate, 'dd mon yy hh24:mi:ss') || utl_tcp.crlf ||
           'From: ' || p_fromuser || '<' || p_from || '>' || utl_tcp.crlf ||
           'To: ' || v_touser1 || utl_tcp.crlf ||
           'Cc: ' || p_cc || utl_tcp.crlf ||
           'Subject: ' || p_subject || utl_tcp.crlf ||
           utl_tcp.crlf ||  -- 空行分隔 Header/Body
           p_message;

  -- 7. 發送資料(指定 UTF-8 避免中文亂碼)
  utl_smtp.open_data(v_conn);
  utl_smtp.write_raw_data(v_conn,
    utl_raw.cast_to_raw(convert('Content-Type: text/html; charset=utf-8' || v_msg, 'ZHS16GBK')));
  utl_smtp.close_data(v_conn);
  utl_smtp.quit(v_conn);

exception
  when others then
    str_error := dbms_utility.format_error_stack || dbms_utility.format_call_stack;
    dbms_output.put_line(str_error);
    -- 實務建議寫入錯誤日誌表
end;
/

呼叫範例

begin
  send_mail_(
    p_from      => 'noreply@example.com',
    p_fromuser  => '系統通知',
    p_touser    => '張三;李四',
    p_to        => 'user1@example.com;user2@example.com',
    p_cc        => 'manager@example.com',
    p_subject   => '測試郵件 - ' || to_char(sysdate, 'YYYY-MM-DD HH24:MI'),
    p_message   => '

HTML 內容測試

支援中文與 粗體。

', p_user => 'smtp_user', p_mailhost => 'smtp.example.com', p_psd => 'smtp_password' ); end; /

關鍵技術點解析

技術用途
UTL_SMTP.EHLO啟用 ESMTP,支援 AUTH、STARTTLS 等擴展指令
AUTH LOGINBase64 編碼帳號/密碼進行 SMTP 認證
UTL_ENCODE.BASE64_ENCODE將帳號密碼轉為 Base64 字串
UTL_RAW.CAST_TO_RAW/VARCHAR2RAW ↔ VARCHAR2 互轉,處理二進位資料
CONVERT(..., 'ZHS16GBK')將 UTF-8 字串轉為資料庫字元集再傳送
Content-Type: text/html; charset=utf-8宣告郵件為 HTML 格式且 UTF-8 編碼

進階擴充建議

  • SSL/TLS (465/587 埠):Oracle 11g+ 支援 UTL_SMTP.STARTTLS,或使用 Oracle Wallet 搭配 UTL_HTTP 呼叫外部 API
  • 附件支援:需手動組裝 MIME multipart/mixed 格式,建議改用 APEX_MAIL (APEX 環境) 或 Java Stored Procedure
  • 非同步發送:搭配 DBMS_SCHEDULER 或 Advanced Queuing (AQ) 避免阻塞主交易
  • 錯誤處理:例外區塊建議寫入自訂錯誤日誌表,並可整合監控告警
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved