You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在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

火山引擎 最新活动