Oracle发送邮件时附件为空的问题求助
Oracle发送邮件时附件为空的问题求助
你好,我看到你遇到了Oracle发送邮件时附件为空的困扰——服务器上用spool生成的SQL结果文件明明有内容,但邮件里的附件却是空的。结合你给出的PL/SQL代码,我来帮你梳理下问题所在和解决办法:
核心问题分析
从你的代码来看,有两个关键参数传递错误:
p_attach_mime参数误用:这个参数应该传入附件的MIME类型(比如CSV文件对应的text/csv),但你现在传的是服务器上的文件路径/home/oracle/pj,这完全不符合参数的预期用途。- 附件内容未正确传入:你给
p_attach_clob传的是固定字符串'MayBe',而不是服务器上那个CSV文件的实际内容,这直接导致邮件附件里没有你想要的文件数据。
解决步骤
要把服务器上的CSV文件作为附件发送,你需要先将文件内容读取到CLOB变量中,再传递给邮件存储过程。具体操作如下:
1. 准备文件访问权限(如果还没配置)
首先需要创建Oracle目录对象并授予权限,让Oracle能访问你的文件目录:
-- 创建目录对象,指向你的CSV文件所在路径 CREATE OR REPLACE DIRECTORY CSV_DIR AS '/home/oracle/pj'; -- 授予当前用户读取该目录的权限 GRANT READ ON DIRECTORY CSV_DIR TO YOUR_ORACLE_USER; -- 授予用户使用UTL_FILE的权限(如果没有的话) GRANT EXECUTE ON UTL_FILE TO YOUR_ORACLE_USER;
注意替换YOUR_ORACLE_USER为你实际使用的Oracle用户名。
2. 修改PL/SQL代码,读取文件内容并发送邮件
下面是修改后的完整代码,它会先读取服务器上的table.csv文件内容到CLOB,再调用邮件存储过程发送:
DECLARE l_clob CLOB; l_file UTL_FILE.FILE_TYPE; l_buffer VARCHAR2(32767); BEGIN -- 初始化临时CLOB存储文件内容 DBMS_LOB.CREATETEMPORARY(l_clob, TRUE); -- 打开服务器上的CSV文件(CSV_DIR是我们创建的目录对象) l_file := UTL_FILE.FOPEN('CSV_DIR', 'table.csv', 'R', 32767); -- 循环读取文件内容到CLOB LOOP BEGIN UTL_FILE.GET_LINE(l_file, l_buffer); -- 将读取到的行写入CLOB DBMS_LOB.WRITEAPPEND(l_clob, LENGTH(l_buffer), l_buffer); -- 补充换行符(因为UTL_FILE.GET_LINE会去掉行尾的换行) DBMS_LOB.WRITEAPPEND(l_clob, 1, CHR(10)); EXCEPTION WHEN NO_DATA_FOUND THEN -- 文件读取完毕,退出循环 EXIT; END; END LOOP; -- 关闭文件 UTL_FILE.FCLOSE(l_file); -- 调用发送邮件的存储过程 send_mail_bis_bis( p_to => 'toto@gmail.com', p_from => 'toto@gmail.com', p_subject => 'result', p_text_msg => 'Maintenant reste la requête à bien la mettre dedans :) ', p_attach_name => 'table.csv', p_attach_mime => 'text/csv', -- 正确的CSV文件MIME类型 p_attach_clob => l_clob, -- 传入读取到的文件内容 p_smtp_host => 'smtp.domaine.fr' ); -- 释放临时CLOB DBMS_LOB.FREETEMPORARY(l_clob); EXCEPTION WHEN utl_smtp.Transient_Error OR utl_smtp.Permanent_Error THEN raise_application_error(-20000, 'Unable to send mail: '||sqlerrm); WHEN OTHERS THEN -- 异常处理:确保文件和CLOB被正确释放 IF UTL_FILE.IS_OPEN(l_file) THEN UTL_FILE.FCLOSE(l_file); END IF; IF DBMS_LOB.ISTEMPORARY(l_clob) = 1 THEN DBMS_LOB.FREETEMPORARY(l_clob); END IF; raise_application_error(-20001, 'Error occurred: '||sqlerrm); END; /
额外注意事项
- 确保服务器上的
/home/oracle/pj/table.csv文件确实存在,且Oracle进程对该目录和文件有读取权限(可以通过chmod和chown命令调整权限)。 - 如果你的
send_mail_bis_bis存储过程支持直接传入文件路径而不是CLOB,那你可以查看它的文档调整参数,但从当前代码逻辑来看,它是通过CLOB接收附件内容的,所以上面的方法是适用的。
备注:内容来源于stack exchange,提问作者Ast
相关产品推荐
相关产品推荐

