多次调用utl_smtp.write_raw_data来附加blob文件

时间:2013-08-30 16:22:11

标签: oracle plsql

我有一个存储在PL / SQL blob变量attachment_blob_中的有效文件。假设文件的大小足够小,以下过程可以将文件附加到电子邮件中。

PROCEDURE Write_Mail_Attachment IS BEGIN
    Write_Part_Boundary (OUTER_BOUNDARY_);
    utl_smtp.write_data (
        smtp_conn_,
        'Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; ' ||
        'name="' || attachment_name_ || '"' || utl_tcp.crlf ||
        'Content-Transfer-Encoding: base64' || utl_tcp.crlf ||
        'Content-Disposition: attachment;filename="'||attachment_name_||'"'||utl_tcp.crlf||utl_tcp.crlf
    );
    utl_smtp.write_raw_data (smtp_conn_, utl_encode.base64_encode(attachment_blob_));
END Write_Mail_Attachment;

(为了避免含糊不清或“你检查过这种”答案,所有变量有效。此块中未定义的任何变量都属于父范围。)

当变量attachment_blob_大于特定大小时,我的问题就开始了。它变得太大而无法由utl_encode.base64_encode()函数处理,并产生数值或值错误。

好的,我告诉自己,没关系。我需要做的就是将blob分成多个块。所以我修改程序如下:

PROCEDURE Write_Mail_Attachment IS
    chunk_size_    NUMBER := 1900;
    offset_        NUMBER := 1;
    file_chunk_    RAW(1900);
BEGIN
    Write_Part_Boundary (OUTER_BOUNDARY_);
    utl_smtp.write_data (
        smtp_conn_,
        'Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; ' ||
        'name="' || attachment_name_ || '"' || utl_tcp.crlf ||
        'Content-Transfer-Encoding: base64' || utl_tcp.crlf ||
        'Content-Disposition: attachment; filename="'||attachment_name_||'"'||utl_tcp.crlf||utl_tcp.crlf
    );
    WHILE offset_ < Dbms_Lob.GetLength(attachment_blob_) LOOP
        Dbms_Lob.Read (attachment_blob_, chunk_size_, offset_, file_chunk_);
        utl_smtp.write_raw_data (smtp_conn_, utl_encode.base64_encode(file_chunk_));
        offset_ := offset_ + chunk_size_;
    END LOOP;
END Write_Mail_Attachment;

现在,此过程执行时没有错误,因为块大小永远不会太大而无法管理utl_encode.base64_encode()。但现在问题是附加文件到达我的收件箱时已损坏。

当我调查“原始”电子邮件内容时,我可以看到附件内容字符串被裁剪为大约1900个字符。如果我将block_size_变量定义为50(而不是1900),则电子邮件中的原始内容将被截断为大约50个字符。换句话说,好像过程utl_smtp.write_raw_data()在循环的每次迭代中都覆盖了文件内容的前一部分,所以我只能在电子邮件中找到文件的最后一块何时发送。

我已经验证了utl_smtp.write_raw_data()上的文档,该文档确认将附加电子邮件,而不是覆盖最后一个块。

我还在Oracle留言板上寻找解决方案,(事实上,我上面的第二个程序来自我在那里发现的一些帖子)。但是,我还没能完全发送附件。

有人能看出我做错了吗?

1 个答案:

答案 0 :(得分:1)

你必须记住,Base64将3个字节编码为4个字节,当最后一个组包含少于3个字节时使用'=',检查Wikipedia上的填充部分。字符'='只能放在编码文档的末尾。这就是为什么你的缓冲区长度必须是三的倍数。