使用 PLSQL 发送电子邮件

Posted

技术标签:

【中文标题】使用 PLSQL 发送电子邮件【英文标题】:Send Email Using PLSQL 【发布时间】:2016-03-02 10:29:23 【问题描述】:

我想使用 PL_SQL 通过 gmail 或 yahoo 主机发送电子邮件,我在 google 中搜索并找到了 SMT.Mail 包,但它对我不起作用,请任何人指导我如何实现这个目标?

CREATE OR REPLACE PROCEDURE 
      send_mail (sender    IN VARCHAR2, 
                 recipient IN VARCHAR2, 
                 message   IN VARCHAR2, 
                 nStatus   OUT NUMBER) 
IS 
    mailhost    VARCHAR2(30) := 'smtp.gmail.com '; -- host mail addr 
    mail_conn  utl_smtp.connection; 
BEGIN 
    nStatus := 0; 
    mail_conn := utl_smtp.open_connection(mailhost, 25); 
    utl_smtp.helo(mail_conn, mailhost); 
    utl_smtp.mail(mail_conn, sender); 
    utl_smtp.rcpt(mail_conn, recipient); 
    utl_smtp.data(mail_conn, message); 
    utl_smtp.quit(mail_conn); 
EXCEPTION 
    WHEN OTHERS THEN 
        nStatus := SQLCODE; 
END send_mail;

当我测试这个程序时,我得到:ORA-29278: SMTP transient error: 421 Service not available

【问题讨论】:

“它对我不起作用”是什么意思?你得到什么错误?请显示您的一些代码。 错误信息是什么? @Wernfried Domscheit 这是我测试此过程时出现的错误:ORA-29278: SMTP 瞬态错误:421 服务不可用 【参考方案1】:

您错过了在服务器上的身份验证,请参阅AUTH Function and Procedure

但是,我不知道gmail是否允许使用默认不安全的端口25。

【讨论】:

【参考方案2】:

我的经验是 utl_mail 包更容易使用。这是一个愚蠢的例子:

BEGIN
   UTL_MAIL.send (sender     => 'bighearted@somewhere.com'
                , recipients => 'receiver@footballreceiver.com'
                , subject    => 'Goofy Messages'
                , MESSAGE    => 'Please don''t send any more goofy messages'
                , mime_type  => 'text/html; charset=us-ascii');
 END;

您必须将系统参数 smtp_out_server 设置为您的电子邮件服务器的名称。

对于 Oracle 11G R2 及更高版本,您必须设置正确的访问控制列表 (ACL) 才能使其正常工作。这是我用来执行此操作的代码。

DECLARE
   -- ACL name to be used for email access reuse the same value for all 
   -- future calls
   l_acl         VARCHAR2 (30) := 'utl_smtp.xml';
   -- Oracle user to be given permission to send email
   l_principal   VARCHAR2 (30) := 'CEAADMIN';
   -- Name of email server
   g_mailhost    VARCHAR2 (60) := 'mail.yourserver.com';
   l_cnt         INTEGER;

   PROCEDURE validate_smtp_server
   AS
      l_value       v$parameter.VALUE%TYPE;
      l_parameter   v$parameter.name%TYPE := 'smtp_out_server';
   BEGIN

      SELECT VALUE
        INTO l_value
        FROM v$parameter
       WHERE name = l_parameter;

      IF l_value IS NULL
      THEN
         raise_application_error (
            -20001
          ,    'Oracle parameter '
            || l_parameter
            || ' has not been set'
            || UTL_TCP.crlf
            || 'it s/b mail.yourserver.com'
         );
      END IF;

      DBMS_OUTPUT.put_line ('parameter ' || l_parameter || ' value is ' ||     l_value);

   END validate_smtp_server;

   PROCEDURE create_if_needed (p_acl IN VARCHAR2)
   AS
      l_cnt   INTEGER;
   BEGIN

      SELECT COUNT (*) c
        INTO l_cnt
        FROM dba_network_acls a
       WHERE SUBSTR (acl, INSTR (acl, '/', -1) + 1) = p_acl;

      IF l_cnt = 0
      THEN
         DBMS_OUTPUT.put_line ('creating acl ' || p_acl);
         DBMS_NETWORK_ACL_ADMIN.create_acl (
            acl         => p_acl
          , description => 'Allow use of utl_smtp'
          , principal   => l_principal
          , is_grant    => TRUE
          , privilege   => 'connect'
         );

         DBMS_NETWORK_ACL_ADMIN.assign_acl (acl => p_acl, HOST => g_mailhost);
         COMMIT;
      ELSE
         DBMS_OUTPUT.put_line (p_acl || ' acl already exists');
      END IF;

   END create_if_needed;

   PROCEDURE add_if_needed (
      p_principal   IN VARCHAR2
    , p_acl         IN VARCHAR2
   )
   AS
      l_cnt   INTEGER;
   BEGIN

      SELECT COUNT (*) c
        INTO l_cnt
        FROM dba_network_acl_privileges
       WHERE SUBSTR (acl, INSTR (acl, '/', -1) + 1) = p_acl
         AND principal = p_principal;

      IF l_cnt = 0
      THEN
         DBMS_NETWORK_ACL_ADMIN.add_privilege (
            acl       => 'utl_smtp.xml'
          , principal => p_principal
          , is_grant  => TRUE
          , privilege => 'connect'
         );
         COMMIT;
         DBMS_OUTPUT.put_line ('access to ' || p_acl || ' added for ' ||     p_principal);
      ELSE
         DBMS_OUTPUT.put_line (p_principal || ' already has access to ' || p_acl);
      END IF;

   END add_if_needed;
BEGIN

   EXECUTE IMMEDIATE 'grant execute on utl_mail to ' || l_principal;

   create_if_needed (p_acl => l_acl);
   add_if_needed (p_principal => l_principal, p_acl => l_acl);
   DBMS_OUTPUT.put_line ('Verification SQL:');
   DBMS_OUTPUT.put_line ('    SELECT * FROM dba_network_acls;');
   DBMS_OUTPUT.put_line ('    SELECT * FROM dba_network_acl_privileges;');
   COMMIT;
   validate_smtp_server;
END;

【讨论】:

嗨@brian-leach,我正在尝试上面提到的脚本,但我收到了错误PLS-00201: identifier 'DBMS_NETWORK_ACL_ADMIN' must be declared,可能是由于缺乏对DBMS_NETWORK_ACL_ADMIN 的授权,是否有可能使用另一个用户运行它?谢谢! 抱歉回复晚了,圣日我一直在度假。必须由具有 DBA 权限的人为您运行此脚本。

以上是关于使用 PLSQL 发送电子邮件的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 Java 的情况下压缩 .csv 文件并在电子邮件中附加 Oracle plsql

Oracle PLSQL通过SMTP发送E-MAIL邮件代码

PLSQL Case 语句比较两列

在 PLSQL 中检查电子邮件的域

PLSQL图形界面设置oracle的JOBS

PLSQL图形界面设置oracle的JOBS