如何在Oracle APEX中通过非本地未加密SMTP服务器使用UTL_SMTP发送邮件
用UTL_SMTP通过非本地未加密SMTP服务器发送邮件(带身份验证)
嘿,这个问题我熟!UTL_SMTP确实没有把账号密码做成直接传入的函数参数,但咱们可以通过手动发送SMTP的AUTH身份验证命令来实现,核心就是利用SMTP协议的扩展命令完成登录。下面给你一步步拆解,还有完整的代码示例:
核心原理
SMTP协议的身份验证是通过AUTH扩展命令完成的,UTL_SMTP虽然没有封装这个命令,但提供了UTL_SMTP.COMMAND方法让我们直接发送原始SMTP命令,结合UTL_ENCODE做base64编码(因为AUTH LOGIN/PLAIN要求账号密码用base64传输),就能搞定身份验证。
具体步骤&代码示例
下面是一个完整的PL/SQL示例,假设你的SMTP服务器地址是smtp.example.com,端口是25(未加密),账号是your_email@example.com,密码是your_password:
DECLARE v_smtp_host VARCHAR2(50) := 'smtp.example.com'; v_smtp_port NUMBER := 25; -- 未加密常用端口还有587,根据你的服务器调整 v_username VARCHAR2(100) := 'your_email@example.com'; v_password VARCHAR2(100) := 'your_password'; v_conn UTL_SMTP.CONNECTION; v_base64_user VARCHAR2(200); v_base64_pwd VARCHAR2(200); BEGIN -- 1. 连接到SMTP服务器 v_conn := UTL_SMTP.OPEN_CONNECTION(v_smtp_host, v_smtp_port); -- 2. 发送EHLO命令(必须,因为要启用SMTP扩展命令,包括AUTH) UTL_SMTP.EHLO(v_conn, UTL_INADDR.GET_HOST_NAME); -- 3. 发起身份验证:先发送AUTH LOGIN命令 UTL_SMTP.COMMAND(v_conn, 'AUTH', 'LOGIN'); -- 4. 发送base64编码的用户名(注意去掉base64编码后的换行符) v_base64_user := REPLACE(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(v_username)), CHR(10)||CHR(13), ''); UTL_SMTP.COMMAND(v_conn, v_base64_user); -- 5. 发送base64编码的密码 v_base64_pwd := REPLACE(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(v_password)), CHR(10)||CHR(13), ''); UTL_SMTP.COMMAND(v_conn, v_base64_pwd); -- 6. 常规发邮件流程:设置发件人 UTL_SMTP.MAIL(v_conn, 'sender@example.com'); -- 7. 设置收件人(多个收件人可以多次调用RCPT) UTL_SMTP.RCPT(v_conn, 'recipient@example.com'); -- 8. 开始发送邮件内容 UTL_SMTP.DATA(v_conn, 'From: "发送者名称" <sender@example.com>' || UTL_TCP.CRLF || 'To: "接收者名称" <recipient@example.com>' || UTL_TCP.CRLF || 'Subject: 测试邮件' || UTL_TCP.CRLF || UTL_TCP.CRLF || '这是用UTL_SMTP带身份验证发送的测试邮件内容!' ); -- 9. 关闭连接 UTL_SMTP.QUIT(v_conn); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('发送失败:' || SQLERRM); -- 异常时尽量关闭连接,避免资源泄漏 IF UTL_SMTP.IS_OPEN(v_conn) THEN UTL_SMTP.QUIT(v_conn); END IF; RAISE; END; /
关键注意事项
- AUTH命令类型:有些SMTP服务器可能要求用
AUTH PLAIN而不是AUTH LOGIN,这时候格式要调整:把用户名和密码用NULL字符分隔后再base64编码,然后一次性发送。比如:v_auth_str := UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW('' || CHR(0) || v_username || CHR(0) || v_password)); UTL_SMTP.COMMAND(v_conn, 'AUTH', 'PLAIN ' || v_auth_str); - 权限问题:执行这个PL/SQL块的数据库用户需要被授予
EXECUTE权限:GRANT EXECUTE ON UTL_SMTP TO your_user; GRANT EXECUTE ON UTL_ENCODE TO your_user; - 端口选择:未加密的SMTP服务器常用端口是25(默认SMTP端口)或587(提交端口,很多服务商推荐用这个),如果25端口被防火墙拦截,试试587。
- 编码处理:base64编码后可能会自动添加换行符,一定要用
REPLACE去掉,否则SMTP服务器会识别错误。
内容的提问来源于stack exchange,提问作者ProgNi




