Oracle电子邮件发送日期有时不正确

Dee*_*ent 3 email oracle plsql oracle10g oracle11g

我有一个生产问题涉及Oracle 11g电子邮件发送日期.代码如下.

  procedure email(p_recip   in apex_application_global.vc_arr2,
                  p_subject in varchar2,
                  p_message in varchar2) is

    c                  utl_smtp.connection;
    msg                varchar2(4000);
    username           varchar2(100) := 'XXX';
    password           varchar2(100) := '123';
    l_encoded_username varchar2(200);
    l_encoded_password varchar2(200);
    l_recips           varchar2(2000);

    procedure send_header(name in varchar2, header in varchar2) as
    begin
      utl_smtp.write_data(c, name || ': ' || header || utl_tcp.crlf);
    end;
  begin
    --Open SMTP connection
    l_encoded_username := utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(username)));
    l_encoded_password := utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(password)));
    c                  := utl_smtp.open_connection('AAA.BBB.local', '25');
    utl_smtp.ehlo(c, 'AAA.BBB.local'); --DO NOT USE HELO
    utl_smtp.command(c, 'AUTH', 'LOGIN');
    utl_smtp.command(c, l_encoded_username);
    utl_smtp.command(c, l_encoded_password);
    utl_smtp.mail(c, 'XXX@YYY.on.ca');

    if ((p_recip is null) or p_recip.count = 0) then
      return;
    end if;

    for i in 1 .. p_recip.count loop
      utl_smtp.rcpt(c, p_recip(i));
      l_recips := l_recips || p_recip(i) || ','; --mark as Multiple receivers
    end loop;

    --now remove the trailing comma at the end of l_recips
    l_recips := substr(l_recips, 0, length(l_recips) - 1);

    utl_smtp.open_data(c);

    --prepare mail header
    utl_smtp.write_data(c, 'Date: ' ||
                         to_char(sysdate, 'MM-DD-YYYY HH24:MI:SS') ||
                         utl_tcp.crlf);

    utl_smtp.write_data(c, 'To: ' || l_recips || utl_tcp.crlf);

    utl_smtp.write_data(c, 'From: ' ||
                         '"Company" <MMM@KKK.on.ca>' ||
                         utl_tcp.crlf);
    utl_smtp.write_data(c, 'Subject: ' || p_subject || utl_tcp.crlf ||
                         utl_tcp.crlf);

    --include the message body
    utl_smtp.write_data(c, msg);

    -- Write message body
    utl_smtp.write_data(c, p_message || utl_tcp.crlf);

    -- Clean up
    utl_smtp.close_data(c);
    utl_smtp.quit(c);

  exception
    when utl_smtp.transient_error or utl_smtp.permanent_error then
      begin
        utl_smtp.quit(c);
      exception
        when utl_smtp.transient_error or utl_smtp.permanent_error then
          null;
          -- When the SMTP server is down or unavailable, we don't have
        -- a connection to the server. The QUIT call will raise an
        -- exception that we can ignore.
      end;

      raise_application_error(-20000, 'Failed to send mail due to the following error: ' ||
                               sqlerrm);
  end;

------------------------------------------

Unfortunately, the date on received email "Sent:" some times are wrong.  
For example :
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

在此输入图像描述

在此输入图像描述

Ale*_*ole 9

数据格式在RFC 822中指定(在RFC1123中添加了四位数年份).您以不同的格式发送日期.看起来这有时被接受,有时候不被接受; 并且正在给出'错误'的结果.文件夹视图中的日期是接收日期,而不是发送日期,因此它实际上没有任何影响 - 除了它与消息正文中的日期对齐作为有用的交叉引用.

你这样做:

utl_smtp.write_data(c, 'Date: ' ||
                     to_char(sysdate, 'MM-DD-YYYY HH24:MI:SS') ||
                     utl_tcp.crlf);
Run Code Online (Sandbox Code Playgroud)

所以现在我得到的价值Date: 05-09-2014 17:43:28.根据应解释为2014-09-05(9月5日)的RFC .您似乎有时会发现,但并非总是如此,这表明MTA的处理方式不同.基于这三个例子,这可能取决于"错误"日期是否有效.如果我发送邮件的那个日期确实出现在Outlook中2014-09-05; 但如果我将其更改为05-23-2014 17:43:28然后它会通过正确的日期 - 可能是因为无效日期2014-23-05被静默拒绝,而MTA使用其当前日期.(或者客户端;事实上可能更有可能).

你似乎在第二个例子中有一个进一步的扭曲,因为它显示06/10/2013而不是,正如你可能期望的那样形成'正确'的日期,06/11/2013.我认为那是因为你也失去了时区偏移; 实际上你并没有设置一个,但是当你调整它时,你可能仍然会越过日期边界.

因此,请按RFC期望格式化您的日期:

utl_smtp.write_data(c, 'Date: ' ||
                     to_char(systimestamp, 'Dy DD Mon YYYY HH24:MI:SS TZH:TZM',
                         'NLS_DATE_LANGUAGE=ENGLISH') ||
                     utl_tcp.crlf);
Run Code Online (Sandbox Code Playgroud)

这使:

Date: Fri 09 May 2014 17:47:52 +01:00
Run Code Online (Sandbox Code Playgroud)

在我的BST时区.请注意,您必须使用systimestamp而不是sysdate获取时区信息.它必须是英文的,所以我添加了可选的第三个参数,to_char()以确保无论会话区域设置如何都是如此.


正如@ShoeLace在评论中提到的那样,上面的字符串仍然不能与RFC 822完全匹配,它可能应该是:

utl_smtp.write_data(c, 'Date: ' ||
                     to_char(systimestamp, 'Dy, DD Mon YYYY HH24:MI:SS TZHTZM',
                         'NLS_DATE_LANGUAGE=ENGLISH') ||
                     utl_tcp.crlf);
Run Code Online (Sandbox Code Playgroud)

现在给出:

Date: Tue, 04 Aug 2015 10:09:31 +0100
Run Code Online (Sandbox Code Playgroud)

有些服务器可以接受没有逗号或冒号,但最好是正确的...