【问题标题】:ACL error when trying to send mail via Oracle UTL_SMTP尝试通过 Oracle UTL_SMTP 发送邮件时出现 ACL 错误
【发布时间】:2018-12-19 23:28:33
【问题描述】:

我试图通过 oracle utl_smtp 发送电子邮件,但每次执行 apex_mail_p.mail 程序时都会收到 ACL 错误,更准确地说是错误 ORA-24247。但我已经创建了 acl,添加了正确的权限,并将主机和端口添加到 ACL。我不明白为什么它给了我一个错误。

这是代码:

    -- create acl
begin
        dbms_network_acl_admin.create_acl (
                acl             => 'gmail.xml',
                description     => 'Normal Access',
                principal       => 'CONNECT',
                is_grant        => TRUE,
                privilege       => 'connect',
                start_date      => null,
                end_date        => null
        );
end;
/

-- add priviliege to acl
begin
  dbms_network_acl_admin.add_privilege ( 
  acl       => 'gmail.xml',
  principal    => 'MY_PROJECT',
  is_grant    => TRUE, 
  privilege    => 'connect', 
  start_date    => null, 
  end_date    => null); 
end;
/
-- assign host, port to acl
begin
  dbms_network_acl_admin.assign_acl (
  acl => 'gmail.xml',
  host => 'localhost',
  lower_port => 25,
  upper_port => 25);
end;
/



create or replace package apex_mail_p
is
   g_smtp_host      varchar2 (256)     := 'localhost';
   g_smtp_port      pls_integer        := 25;
   g_smtp_domain    varchar2 (256)     := 'gmail.com';
   g_mailer_id constant varchar2 (256) := 'Mailer by Oracle UTL_SMTP';
   -- send mail using UTL_SMTP
   procedure mail (
      p_sender in varchar2
    , p_recipient in varchar2
    , p_subject in varchar2
    , p_message in varchar2
   );
end;
/
create or replace package body apex_mail_p
is
   -- Write a MIME header
   procedure write_mime_header (
      p_conn in out nocopy utl_smtp.connection
    , p_name in varchar2
    , p_value in varchar2
   )
   is
   begin
      utl_smtp.write_data ( p_conn
                          , p_name || ': ' || p_value || utl_tcp.crlf
      );
   end;
   procedure mail (
      p_sender in varchar2
    , p_recipient in varchar2
    , p_subject in varchar2
    , p_message in varchar2
   )
   is
      l_conn           utl_smtp.connection;
      nls_charset    varchar2(255);
   begin
      -- get characterset
      select value
      into   nls_charset
      from   nls_database_parameters
      where  parameter = 'NLS_CHARACTERSET';
      -- establish connection and autheticate
      l_conn   := utl_smtp.open_connection (g_smtp_host, g_smtp_port);
      utl_smtp.ehlo(l_conn, g_smtp_domain);  
      utl_smtp.command(l_conn, 'auth login');
      utl_smtp.command(l_conn,utl_encode.text_encode('mymail@gmail.com', nls_charset, 1));
      utl_smtp.command(l_conn, utl_encode.text_encode('mypassword123', nls_charset, 1));
      -- set from/recipient
      utl_smtp.command(l_conn, 'MAIL FROM: <'||p_sender||'>');
      utl_smtp.command(l_conn, 'RCPT TO: <'||p_recipient||'>');
      -- write mime headers
      utl_smtp.open_data (l_conn);
      write_mime_header (l_conn, 'From', p_sender);
      write_mime_header (l_conn, 'To', p_recipient);
      write_mime_header (l_conn, 'Subject', p_subject);
      write_mime_header (l_conn, 'Content-Type', 'text/plain');
      write_mime_header (l_conn, 'X-Mailer', g_mailer_id);
      utl_smtp.write_data (l_conn, utl_tcp.crlf);
      -- write message body
      utl_smtp.write_data (l_conn, p_message);
      utl_smtp.close_data (l_conn);
      -- end connection
      utl_smtp.quit (l_conn);
   exception
      when others
      then
         begin
           utl_smtp.quit(l_conn);
         exception
           when others then
             null;
         end;
         raise_application_error(-20000,'Failed to send mail due to the following error: ' || sqlerrm);   
   end;
end;
/



begin
   apex_mail_p.mail('mymail@gmail.com', 'test@gmail.com', 'Test', 'Its only a test');
end;
/

【问题讨论】:

  • 查看视图 - dba_network_acl_privileges 和 dba_network_acls 并查看它们是否正确。为确保不是网络问题,通过命令行登录db服务器,在25端口执行telnet,看看你得到了什么。
  • 我确实从 dba_network_acls 中选择了 *,并且所有权限都设置为“连接”,我还执行了 telnet localhost 25,它给了我这个:220 smtp.gmail.com ESMTP o15sm3627998wrp.12 - gsmtp

标签: oracle plsql ora-24247


【解决方案1】:
  • principal 参数替换为您的数据库用户名,
  • 还添加解析权限,
  • 不需要使用冗余的begin..end 块。

所以你可以考虑使用下面的:

    -- create acl
    begin
      dbms_network_acl_admin.create_acl (
      acl             => 'gmail.xml',
      description     => 'Normal Access',
      principal       => 'DB_USER',
      is_grant        => TRUE,
      privilege       => 'connect',
      start_date      => null,
      end_date        => null);

    -- add priviliege to acl
      dbms_network_acl_admin.add_privilege ( 
      acl       => 'gmail.xml',
      principal    => 'DB_USER',
      is_grant    => TRUE, 
      privilege    => 'connect', 
      start_date    => null, 
      end_date    => null); 

      dbms_network_acl_admin.add_privilege ( 
      acl       => 'gmail.xml',
      principal    => 'DB_USER',
      is_grant    => TRUE, 
      privilege    => 'resolve', 
      start_date    => null, 
      end_date    => null);       

      -- assign host, port to acl
      dbms_network_acl_admin.assign_acl (
      acl => 'gmail.xml',
      host => 'localhost',
      lower_port => 25,
      upper_port => 25);
    end;
    /

【讨论】:

  • 谢谢@Barbaros Özhan 的回答,原来我使用了错误的数据库用户。
【解决方案2】:

host 是您要连接的主机名,即 gmail 服务器。我假设 gmail 不允许普通的 smtp,您必须使用端口 465 用于 SSL 或 587 用于 TLS/STARTTLS。

begin
  dbms_network_acl_admin.assign_acl (
  acl => 'gmail.xml',
  host => 'smtp.gmail.com', -- or host => 'gmail.com', - I never used gmail in Oracle
  lower_port => 465,
  upper_port => 465);
end;

你也可以试试

begin
  dbms_network_acl_admin.assign_acl (
  acl => 'gmail.xml',
  host => '*');
end;

但是,Oracle DB 可以连接到任何端口上的任何服务器,因此出于安全原因,您应该仅将其用于测试(除非您的 Oracle 服务器和互联网之间有外部防火墙)

【讨论】:

  • 我最终使用端口 25 和 localhost 作为主机。我还使用了第三方工具 Stunnel 进行 SSL 封装。
猜你喜欢
  • 1970-01-01
  • 2018-02-04
  • 2014-03-22
  • 2016-06-15
  • 2012-08-23
  • 2011-04-05
  • 1970-01-01
  • 2023-01-29
相关资源
最近更新 更多