郵件是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
特此免費授予任何獲得此軟件副本和相關文檔文件(“軟件”)的人,以無限制處理該軟件,包括無限制的使用權,複製,修改,修改,合併,發布,分發,分佈和/或出售該軟件的副本,並允許提供該軟件的人,但要遵守以下條件:
上述版權通知和此許可通知應包含在軟件的所有副本或大量部分中。
該軟件是“按原樣”提供的,沒有任何形式的明示或暗示保證,包括但不限於適銷性,適合特定目的和非侵害的保證。 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE軟體.