邮件是Ruby的Internet库,旨在以简单的红宝石方式处理电子邮件生成,解析和发送。
该库的目的是提供一个访问点来处理所有电子邮件功能的访问点,包括发送和接收电子邮件。所有网络类型操作均通过net :: SMTP,net :: pop3等来完成。
它是根据我在Tmail的经验而建立的,它的目的是成为纯粹的红宝石实现,它使生成,发送和解析电子邮件变得无所适从。
它也是从头开始设计的,可以与Ruby更现代的版本一起工作。现代红宝石的处理文本编码比以前更奇妙,因此这些功能在此库中得到了充分的优势,允许邮件比Tmail更干净地处理消息更多。
最后,邮件是使用一个非常简单的面向对象的系统设计的,该系统确实可以打开您正在解析的电子邮件,如果您知道自己在做什么,则可以直接在电子邮件中直接摆弄。
是的,你!邮件被世界各地的人们用于无数应用程序。与所有开源软件一样,它是我们业余时间所承受的爱的劳动。如果您想表示感谢,请与我们一起挖掘并做出贡献!分类和修复GitHub问题,改进我们的文档,添加新功能 - 向您添加!谢谢您的投球。
邮件已针对:
随着新版本的Ruby发布,邮件将与对“预览”和所有“正常维护”,“安全维护”以及在Ruby Vaintenance分支页面上列出的两个最新“生命终结”版本的支持兼容。欢迎拉动请求以帮助增加对新预览版本的支持。
每个邮件提交都通过GitHub操作对所有受支持的Ruby版本进行测试。
如果您想与精明的人讨论邮件,请订阅Google Group。
邮件现在为RFC5322和RFC6532现在符合RFC5322,也就是说,它可以解析US-ASCII和UTF-8电子邮件并生成US-ASCII电子邮件。有几个已过时的电子邮件语法会遇到问题,但这也很健壮,这意味着,如果发现某些东西不了解它不会崩溃,相反,它将跳过问题并继续解析。对于标头,它不了解,它将标题将标题作为可选的非结构化字段初始化并继续解析。
这意味着邮件不会(我认为)将您的数据(我认为)处理。
您还可以创建MIME电子邮件。有一些辅助方法用于为文本/普通和文本/HTML(最常见的一对)制作多个替代电子邮件(最常见的一对),您可以手动创建任何其他类型的MIME电子邮件。
下一个托多:
基本上...我们在邮件中进行BDD。没有相应或覆盖规格的没有邮件写的方法。我们期望由RCOV衡量的最低100%覆盖率。尽管这在任何方面都不是完美的,但它还是不错的。此外,Tmail的所有功能测试都将在GEM释放之前通过。
这也意味着您可以确保邮件的行为正确。
您可以通过运行bundle exec rspec
在本地运行测试。
您可以使用ACT对所有受支持的Ruby版本进行测试。
单点版本中没有API删除。所有删除都将在拆除之前至少释放一个小点释放的警告。
另外,所有被声明的私人或受保护方法 - 尽管这仍然是i/p。
安装非常简单,我在RubyGems上托管邮件,因此您可以做:
# gem install mail
如果您不知道,在电子邮件中处理编码并不像您希望的那样直截了当。
我试图简化一些:
所有可以渲染到电子邮件的对象,都具有#encoded
方法。编码将返回对象,作为准备在邮件系统中发送的完整字符串,即,它将在末端包含标题字段和值和CRLF,并根据需要包装。
所有可以渲染到电子邮件的对象,都具有#decoded
方法。解码将仅作为字符串返回对象的“值”。这意味着它将不包括标题字段(例如:'to:'或'主题:')。
默认情况下,在容器对象上调用#to_s
将调用其编码方法,而字段对象上的#to_s
将调用其解码方法。因此,在邮件对象上调用#to_s
将返回邮件,所有编码已准备好发送,同时呼叫#to_s
在从字段上拨打#to_s,否则正文将返回对象的解码值。邮件的标题对象被视为容器。如果您有疑问,请致电#encoded
或#decoded
,如果不确定,这更安全。
具有可以编码参数值的结构化字段(例如,内容类型)将在将参数名称称为针对对象的方法时提供解码的参数值。
具有可以编码的参数值的结构化字段(例如Content-Type)将在您通过object.parameters['<parameter_name>']
方法调用时调用参数名称时,将提供编码的参数值。
请做!贡献在邮件中很容易。请阅读contruting.md文档以获取更多信息。
所有主要的邮件功能都应从邮件模块中发生。因此,您应该只require 'mail'
才能开始。
mail
在其红宝石代码中已有很好的记录。您可以在rubydoc.info上查找它。
mail = Mail . new do
from '[email protected]'
to '[email protected]'
subject 'This is a test email'
body File . read ( 'body.txt' )
end
mail . to_s #=> "From: [email protected]: you@...
mail = Mail . new do
body File . read ( 'body.txt' )
end
mail [ 'from' ] = '[email protected]'
mail [ :to ] = '[email protected]'
mail . subject = 'This is a test email'
mail . header [ 'X-Custom-Header' ] = 'custom value'
mail . to_s #=> "From: [email protected]: you@...
mail = Mail . new do
to '[email protected]'
body 'Some simple body'
end
mail . to_s =~ /Message - ID: <[ d w _]+@.+.mail/ #=> 27
邮件将自动添加消息ID字段,如果邮件丢失,并沿着以下方式给出一个独特的随机消息-ID。
mail = Mail . new do
to '[email protected]'
message_id '<[email protected]>'
body 'Some simple body'
end
mail . to_s =~ /Message - ID: <[email protected]>/ #=> 27
邮件将使您分配给它的消息_id相信您知道自己在做什么。
邮件默认为通过SMTP发送到本地主机端口25。如果您在此端口上运行Sendmail或Postfix守护程序,则发送电子邮件很容易:
Mail . deliver do
from '[email protected]'
to '[email protected]'
subject 'Here is the image you wanted'
body File . read ( 'body.txt' )
add_file '/full/path/to/somefile.png'
end
或者
mail = Mail . new do
from '[email protected]'
to '[email protected]'
subject 'Here is the image you wanted'
body File . read ( 'body.txt' )
add_file :filename => 'somefile.png' , :content => File . read ( '/somefile.png' )
end
mail . deliver!
通过SendMail发送可以这样做:
mail = Mail . new do
from '[email protected]'
to '[email protected]'
subject 'Here is the image you wanted'
body File . read ( 'body.txt' )
add_file :filename => 'somefile.png' , :content => File . read ( '/somefile.png' )
end
mail . delivery_method :sendmail
mail . deliver
通过SMTP发送(例如,向MailCatcher发送)
Mail . defaults do
delivery_method :smtp , address : "localhost" , port : 1025
end
EXIM需要自己的交货经理,可以这样使用:
mail . delivery_method :exim , :location => "/usr/bin/exim"
mail . deliver
邮件也可以“传递”到日志文件中进行开发和测试:
# Delivers by logging the encoded message to $stdout
mail . delivery_method :logger
# Delivers to an existing logger at :debug severity
mail . delivery_method :logger , logger : other_logger , severity : :debug
您可以在Mail.defaults
中使用retriever_method
配置邮件以接收电子邮件。
# e.g. POP3
Mail . defaults do
retriever_method :pop3 , :address => "pop.gmail.com" ,
:port => 995 ,
:user_name => '<username>' ,
:password => '<password>' ,
:enable_ssl => true
end
# IMAP
Mail . defaults do
retriever_method :imap , :address => "imap.mailbox.org" ,
:port => 993 ,
:user_name => '<username>' ,
:password => '<password>' ,
:enable_ssl => true
end
您可以通过多种方式访问传入的电子邮件。
最新电子邮件:
Mail . all #=> Returns an array of all emails
Mail . first #=> Returns the first unread email
Mail . last #=> Returns the last unread email
按日期按顺序排列的前10封电子邮件:
emails = Mail . find ( :what => :first , :count => 10 , :order => :asc )
emails . length #=> 10
甚至所有电子邮件:
emails = Mail . all
emails . length #=> LOTS!
mail = Mail . read ( '/path/to/message.eml' )
mail . envelope_from #=> '[email protected]'
mail . from . addresses #=> ['[email protected]', '[email protected]']
mail . sender . address #=> '[email protected]'
mail . to #=> '[email protected]'
mail . cc #=> '[email protected]'
mail . subject #=> "This is the subject"
mail . date . to_s #=> '21 Nov 1997 09:55:06 -0600'
mail . message_id #=> '<[email protected]>'
mail . decoded #=> 'This is the body of the email...
还有更多可用的方法。
mail = Mail . read ( 'multipart_email' )
mail . multipart? #=> true
mail . parts . length #=> 2
mail . body . preamble #=> "Text before the first part"
mail . body . epilogue #=> "Text after the last part"
mail . parts . map { | p | p . content_type } #=> ['text/plain', 'application/pdf']
mail . parts . map { | p | p . class } #=> [Mail::Message, Mail::Message]
mail . parts [ 0 ] . content_type_parameters #=> {'charset' => 'ISO-8859-1'}
mail . parts [ 1 ] . content_type_parameters #=> {'name' => 'my.pdf'}
邮件生成零件树。每条消息都有许多或没有零件。每个部分都是可能具有多个或没有零件的另一条消息。
仅当零件是多部分/混合或多部分/相关内容类型并且具有边界定义时,消息才会具有零件。
mail . attachments . each do | attachment |
# Attachments is an AttachmentsList object containing a
# number of Part objects
if ( attachment . content_type . start_with? ( 'image/' ) )
# extracting images for example...
filename = attachment . filename
begin
File . open ( images_dir + filename , "w+b" , 0644 ) { | f | f . write attachment . decoded }
rescue => e
puts "Unable to save data for #{ filename } because #{ e . message } "
end
end
end
邮件做出了一些基本的假设,并使通用的事情尽可能简单....(从邮件库中询问很多)
mail = Mail . deliver do
part :content_type => "multipart/mixed" do | p1 |
p1 . part :content_type => "multipart/related" do | p2 |
p2 . part :content_type => "multipart/alternative" ,
:content_disposition => "inline" do | p3 |
p3 . part :content_type => "text/plain; charset=utf-8" ,
:body => "Here is the attachment you wanted n "
p3 . part :content_type => "text/html; charset=utf-8" ,
:body => "<h1>Funky Title</h1><p>Here is the attachment you wanted</p> n "
end
end
add_file '/path/to/myfile.pdf'
end
from "Mikel Lindsaar <[email protected]>"
to "[email protected]"
subject "First multipart email sent with Mail"
end
然后,邮件在块的末尾发送电子邮件并返回结果邮件::消息对象,然后您可以检查一下是否需要...
puts mail.to_s #=>
Date: Tue, 26 Apr 2022 20:12:07 +0200
From: Mikel Lindsaar <[email protected]>
To: [email protected]
Message-ID: <[email protected]>
Subject: First multipart email sent with Mail
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="--==_mimepart_626835f733867_10873fdfa3c2ffd494636";
charset=UTF-8
Content-Transfer-Encoding: 7bit
----==_mimepart_626835f733867_10873fdfa3c2ffd494636
Content-Type: multipart/mixed;
boundary="--==_mimepart_626835f73382a_10873fdfa3c2ffd494518";
charset=UTF-8
Content-Transfer-Encoding: 7bit
----==_mimepart_626835f73382a_10873fdfa3c2ffd494518
Content-Type: multipart/related;
boundary="--==_mimepart_626835f7337f5_10873fdfa3c2ffd494438";
charset=UTF-8
Content-Transfer-Encoding: 7bit
----==_mimepart_626835f7337f5_10873fdfa3c2ffd494438
Content-Type: multipart/alternative;
boundary="--==_mimepart_626835f733702_10873fdfa3c2ffd494376";
charset=UTF-8
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Content-ID: <[email protected]>
----==_mimepart_626835f733702_10873fdfa3c2ffd494376
Content-Type: text/plain;
charset=utf-8
Content-Transfer-Encoding: 7bit
Here is the attachment you wanted
----==_mimepart_626835f733702_10873fdfa3c2ffd494376
Content-Type: text/html;
charset=utf-8
Content-Transfer-Encoding: 7bit
<h1>Funky Title</h1><p>Here is the attachment you wanted</p>
----==_mimepart_626835f733702_10873fdfa3c2ffd494376--
----==_mimepart_626835f7337f5_10873fdfa3c2ffd494438--
----==_mimepart_626835f73382a_10873fdfa3c2ffd494518--
----==_mimepart_626835f733867_10873fdfa3c2ffd494636
Content-Type: text/plain;
charset=UTF-8;
filename=myfile.txt
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename=myfile.txt
Content-ID: <6
[email protected]>
Hallo,
Test
End
----==_mimepart_626835f733867_10873fdfa3c2ffd494636--
邮件插入内容传输编码,MIME版本,content-IDS并处理内容类型和边界。
邮件假设,如果您的文本仅是US-ASCII,则您的传输编码为7位,并且是文本/平原。您可以通过明确声明它来覆盖此问题。
您不必在文本中使用块,其中包括HTML零件,您只需声明地做。但是,您需要将邮件::零件添加到电子邮件中,而不是邮件::消息。
mail = Mail . new do
to '[email protected]'
from 'Mikel Lindsaar <[email protected]>'
subject 'First multipart email sent with Mail'
end
text_part = Mail :: Part . new do
body 'This is plain text'
end
html_part = Mail :: Part . new do
content_type 'text/html; charset=UTF-8'
body '<h1>This is HTML</h1>'
end
mail . text_part = text_part
mail . html_part = html_part
使用块表格产生与完成的电子邮件相同的电子邮件
@mail = Mail . read ( '/path/to/bounce_message.eml' )
@mail . bounced? #=> true
@mail . final_recipient #=> rfc822;[email protected]
@mail . action #=> failed
@mail . error_status #=> 5.5.0
@mail . diagnostic_code #=> smtp;550 Requested action not taken: mailbox unavailable
@mail . retryable? #=> false
您可以将文件读取绝对路径,邮件将尝试猜测MIME_TYPE,并为您编码BASE64中的文件。
@mail = Mail . new
@mail . add_file ( "/path/to/file.jpg" )
@mail . parts . first . attachment? #=> true
@mail . parts . first . content_transfer_encoding . to_s #=> 'base64'
@mail . attachments . first . mime_type #=> 'image/jpg'
@mail . attachments . first . filename #=> 'file.jpg'
@mail . attachments . first . decoded == File . read ( '/path/to/file.jpg' ) #=> true
或者,您可以通过file_data传递并给它一个文件名,再次,邮件将尝试为您猜测MIME_TYPE。
@mail = Mail . new
@mail . attachments [ 'myfile.pdf' ] = File . read ( 'path/to/myfile.pdf' )
@mail . parts . first . attachment? #=> true
@mail . attachments . first . mime_type #=> 'application/pdf'
@mail . attachments . first . decoded == File . read ( 'path/to/myfile.pdf' ) #=> true
如果您真的比邮件更了解,那么您也可以覆盖猜测的MIME媒体类型(这很少需要)
@mail = Mail . new
@mail . attachments [ 'myfile.pdf' ] = { :mime_type => 'application/x-pdf' ,
:content => File . read ( 'path/to/myfile.pdf' ) }
@mail . parts . first . mime_type #=> 'application/x-pdf'
当然...邮件也将返回附件
@mail = Mail . new do
to '[email protected]'
from 'Mikel Lindsaar <[email protected]>'
subject 'First multipart email sent with Mail'
text_part do
body 'Here is the attachment you wanted'
end
html_part do
content_type 'text/html; charset=UTF-8'
body '<h1>Funky Title</h1><p>Here is the attachment you wanted</p>'
end
add_file '/path/to/myfile.pdf'
end
@round_tripped_mail = Mail . new ( @mail . encoded )
@round_tripped_mail . attachments . length #=> 1
@round_tripped_mail . attachments . first . filename #=> 'myfile.pdf'
有关更多详细信息,请参见上面的“测试和提取附件”。
如果邮件是系统的一部分,您将需要一种方法来测试它,而无需实际发送电子邮件,TestMailer可以为您执行此操作。
require 'mail'
=> true
Mail . defaults do
delivery_method :test
end
=> #<Mail::Configuration:0x19345a8 @delivery_method=Mail::TestMailer>
Mail :: TestMailer . deliveries
=> [ ]
Mail . deliver do
to '[email protected]'
from '[email protected]'
subject 'testing'
body 'hello'
end
=> #<Mail::Message:0x19284ec ...
Mail :: TestMailer . deliveries . length
=> 1
Mail :: TestMailer . deliveries . first
=> #<Mail::Message:0x19284ec ...
Mail :: TestMailer . deliveries . clear
=> [ ]
还有一组RSSPEC匹配器被Swilda的ActionMailer Matchers窃取/启发(您还需要将delivery_method
设置为上述):
Mail . defaults do
delivery_method :test # in practice you'd do this in spec_helper.rb
end
RSpec . describe "sending an email" do
include Mail :: Matchers
before ( :each ) do
Mail :: TestMailer . deliveries . clear
Mail . deliver do
to [ '[email protected]' , '[email protected]' ]
from '[email protected]'
subject 'testing'
body 'hello'
end
end
it { is_expected . to have_sent_email } # passes if any email at all was sent
it { is_expected . to have_sent_email . from ( '[email protected]' ) }
it { is_expected . to have_sent_email . to ( '[email protected]' ) }
# can specify a list of recipients...
it { is_expected . to have_sent_email . to ( [ '[email protected]' , '[email protected]' ] ) }
# ...or chain recipients together
it { is_expected . to have_sent_email . to ( '[email protected]' ) . to ( '[email protected]' ) }
it { is_expected . to have_sent_email . with_subject ( 'testing' ) }
it { is_expected . to have_sent_email . with_body ( 'hello' ) }
# Can match subject or body with a regex
# (or anything that responds_to? :match)
it { is_expected . to have_sent_email . matching_subject ( /test(ing)?/ ) }
it { is_expected . to have_sent_email . matching_body ( /h(a|e)llo/ ) }
# Can chain together modifiers
# Note that apart from recipients, repeating a modifier overwrites old value.
it { is_expected . to have_sent_email . from ( '[email protected]' ) . to ( '[email protected]' ) . matching_body ( /hell/ )
# test for attachments
# ... by specific attachment
it { is_expected . to have_sent_email . with_attachments ( my_attachment ) }
# ... or any attachment
it { is_expected . to have_sent_email . with_attachments ( any_attachment ) }
# ... or attachment with filename
it { is_expected . to have_sent_email . with_attachments ( an_attachment_with_filename ( 'file.txt' ) ) }
# ... or attachment with mime_type
it { is_expected . to have_sent_email . with_attachments ( an_attachment_with_mime_type ( 'application/pdf' ) ) }
# ... by array of attachments
it { is_expected . to have_sent_email . with_attachments ( [ my_attachment1 , my_attachment2 ] ) } #note that order is important
#... by presence
it { is_expected . to have_sent_email . with_any_attachments }
#... or by absence
it { is_expected . to have_sent_email . with_no_attachments }
end
Spec/Fixtures/emails/From_trec_2005中的规格固定文件来自2005 TREC公共垃圾邮件语料库。根据该项目和许可协议的条款,他们仍然受到版权保护。它们在该项目中用于验证和描述该电子邮件解析器实施的开发。
http://plg.uwaterloo.ca/~gvcormac/treccorpus/
它们被允许使用的“允许使用,第3条”:
"Small excerpts of the information may be displayed to others
or published in a scientific or technical context, solely for
the purpose of describing the research and development and
related issues."
-- http://plg.uwaterloo.ca/~gvcormac/treccorpus/
(麻省理工学院许可证)
版权(C)2009-2016 Mikel Lindsaar
特此免费授予任何获得此软件副本和相关文档文件(“软件”)的人,以无限制处理该软件,包括无限制的使用权,复制,修改,修改,合并,发布,分发,分布和/或出售该软件的副本,并允许提供该软件的人,但要遵守以下条件:
上述版权通知和此许可通知应包含在软件的所有副本或大量部分中。
该软件是“按原样”提供的,没有任何形式的明示或暗示保证,包括但不限于适销性,适合特定目的和非侵害的保证。在任何情况下,作者或版权持有人均不应对任何索赔,损害赔偿或其他责任责任,无论是在合同,侵权或其他方面的诉讼中,与软件或与软件或使用或其他交易有关的诉讼或其他责任软件。