Ruby 发送邮件
使用 Net::SMTP 在 Ruby 中发送电子邮件
Section titled “使用 Net::SMTP 在 Ruby 中发送电子邮件”简单邮件传输协议 (SMTP) 是用于发送电子邮件的标准互联网协议。Ruby 的标准库中包含了 Net::SMTP 类,它提供了连接到 SMTP 服务器并发送电子邮件的客户端接口。
Net::SMTP 提供了建立连接、认证(如果需要)和传输电子邮件消息的方法。使用它的主要方式是使用 Net::SMTP.start 的块形式,它可以自动处理连接的打开和关闭。
Net::SMTP.start 方法接受几个参数来配置连接:
address: SMTP 服务器的主机名或 IP 地址(默认为 ‘localhost’)。port: SMTP 服务器的端口号(默认为 25,标准 SMTP 端口)。helo_domain: 您的客户端用来标识自己的域名(HELO/EHLO 命令,默认为您的系统主机名)。user: 用于 SMTP 认证的用户名(如果需要,默认为nil)。password: 用于 SMTP 认证的密码(如果需要,默认为nil)。authtype: 认证机制(例如:plain、:login、:cram_md5,如果提供了用户则默认为:cram_md5)。
在传递给 start 的块内部,SMTP 实例提供了 send_message 方法,该方法接受:
message_string: 完整的电子邮件消息内容(头部和正文)作为字符串。from_address: 发件人电子邮件地址(用于 MAIL FROM SMTP 命令)。to_addresses: 单个收件人电子邮件地址(字符串)或收件人电子邮件地址数组。
发送基本文本邮件
Section titled “发送基本文本邮件”这里是一个发送电子邮件的简单示例。这假设 SMTP 服务器在 localhost 上运行且无需认证。在实际应用中,您可能会使用远程 SMTP 服务器,这通常需要认证。
require 'net/smtp'
message_body = <<~MESSAGE_ENDFrom: Your Name <your_email@example.com>To: Recipient Name <recipient_email@example.com>Subject: Test Email from Ruby (Net::SMTP)
This is a test email message sent using Net::SMTP in Ruby.
Regards,Ruby ScriptMESSAGE_END
begin Net::SMTP.start('localhost', 25) do |smtp| smtp.send_message message_body, 'your_email@example.com', 'recipient_email@example.com' end puts "Email sent successfully!"rescue StandardError => e puts "Error sending email: #{e.message}"end注意:<<~MESSAGE_END (波浪线 heredoc) 允许使用带缩进的 heredoc,并移除前导空白字符。邮件头部(From, To, Subject)至关重要,并且必须正确格式化,与正文通过一个空行分隔开。
连接到需要认证的远程 SMTP 服务器:
要使用远程 SMTP 服务器(例如 Gmail、SendGrid 等),您需要知道其地址、端口和您的凭据。
# 泛型认证 SMTP 服务器示例# 替换为您实际的服务器详细信息和凭据# Net::SMTP.start('smtp.your_mail_provider.com',# 587, # TLS/STARTTLS 的常用端口# 'your_helo_domain.com', # 通常是您的发送域名# 'your_username',# 'your_password',# :plain) do |smtp|# # ... smtp.send_message ...# end
# 对于 Gmail,您可能需要启用“低安全性应用访问”或使用应用密码。# Gmail 的 SMTP 服务器:smtp.gmail.com,端口:587 (TLS) 或 465 (SSL - 在 start 之前需要 Net::SMTP.enable_ssl)# 考虑到安全和配置的细微之处,对于 Gmail 等服务,通常最好使用专门的邮件发送 gem。发送 HTML 邮件
Section titled “发送 HTML 邮件”要发送 HTML 格式的电子邮件,您需要将 Content-Type 头部设置为 text/html 并包含一个 MIME-Version 头部。
require 'net/smtp'
html_message = <<~MESSAGE_ENDFrom: Your Name <your_email@example.com>To: Recipient Name <recipient_email@example.com>MIME-Version: 1.0Content-Type: text/html; charset=UTF-8Subject: HTML Test Email from Ruby
<html><body> <h1>Hello from Ruby!</h1> <p>This is an email message sent in **HTML format**.</p> <p><a href="https://www.ruby-lang.org">Visit Ruby's Official Website</a></p></body></html>MESSAGE_END
begin Net::SMTP.start('localhost', 25) do |smtp| smtp.send_message html_message, 'your_email@example.com', 'recipient_email@example.com' end puts "HTML Email sent successfully!"rescue StandardError => e puts "Error sending HTML email: #{e.message}"end发送带附件的邮件
Section titled “发送带附件的邮件”发送附件需要构建一个多部分的 MIME 消息。这涉及定义边界来分隔电子邮件的不同部分(文本正文、HTML 正文、附件)。每个部分都有自己的 Content-Type 和 Content-Disposition 头部。附件通常采用 Base64 编码。
使用原生 Net::SMTP 手动构建多部分邮件可能很复杂。对于健壮的附件处理和多部分邮件,强烈推荐使用专门的邮件发送 gem,如 Mail,因为它能大大简化这些任务。然而,这里是一个使用原生 Net::SMTP 的概念性示例(简化版):
require 'net/smtp'require 'base64' # 用于 Base64.strict_encode64
# --- 配置 ---from_email = 'your_email@example.com'to_email = 'recipient_email@example.com'subject = 'Email with Attachment from Ruby'text_body = "Please find the attached file."file_to_attach_path = './my_document.txt' # 为测试创建此文件
# 如果测试文件不存在,则创建一个模拟文件File.write(file_to_attach_path, "This is a test document.") unless File.exist?(file_to_attach_path)
# --- 读取并编码附件 ---begin file_content = File.read(file_to_attach_path) encoded_content = Base64.strict_encode64(file_content) attachment_filename = File.basename(file_to_attach_path)rescue Errno::ENOENT puts "错误: 附件文件未找到于 #{file_to_attach_path}" exitend
# --- 构建 MIME 消息 ---marker = "MAIL_BOUNDARY_#{Time.now.to_i}_#{rand(1000)}"
message_parts = []message_parts << "From: Your Name <#{from_email}>"message_parts << "To: Recipient Name <#{to_email}>"message_parts << "Subject: #{subject}"message_parts << "MIME-Version: 1.0"message_parts << "Content-Type: multipart/mixed; boundary=\"#{marker}\""message_parts << "\n--#{marker}"message_parts << "Content-Type: text/plain; charset=UTF-8"message_parts << "Content-Transfer-Encoding: 7bit"message_parts << "\n#{text_body}"message_parts << "\n--#{marker}"message_parts << "Content-Type: application/octet-stream; name=\"#{attachment_filename}\""message_parts << "Content-Transfer-Encoding: base64"message_parts << "Content-Disposition: attachment; filename=\"#{attachment_filename}\""message_parts << "\n#{encoded_content}"message_parts << "\n--#{marker}--"
full_message = message_parts.join("\r\n") # 在电子邮件中使用 CRLF 作为行尾符
# --- 发送邮件 ---begin Net::SMTP.start('localhost', 25) do |smtp| smtp.send_message full_message, from_email, to_email end puts "带附件的邮件发送成功!"rescue StandardError => e puts "发送带附件的邮件出错: #{e.message}"end重要注意事项:
- **错误处理:**始终包含
begin…rescue块来捕获潜在错误,如连接失败、认证问题或无效地址。 - **安全性 (TLS/SSL):**对于安全通信,特别是与远程 SMTP 服务器通信时,请确保您正在使用 TLS/STARTTLS(通常在端口 587)或 SSL(通常在端口 465)。
Net::SMTP支持enable_starttls_auto(如果服务器支持)或enable_ssl(用于直接 SSL 连接)。对于enable_ssl,您可能需要使用Net::SMTP.new创建Net::SMTP对象,然后调用enable_ssl,再不带块地调用start,或者使用 OpenSSL 上下文选项。请查看Net::SMTP类的文档获取详细信息。 - **邮件发送 Gem:**对于除了简单邮件之外的任何需求,或者需要模板、高级附件处理以及更易于为各种邮件服务提供商配置的功能,请考虑使用像 Mail (
github.com/mikel/mail) 或 Action Mailer (如果您正在使用 Ruby on Rails) 这样的 gem。这些 gem 抽象化了Net::SMTP的许多复杂性。 - **邮件头部和格式化:**密切关注 RFC 标准关于邮件头部和 MIME 格式的要求,以确保您的电子邮件能被各种电子邮件客户端正确渲染。
详细信息请参考 Net::SMTP 类的 Ruby 官方文档。