Le courrier est une bibliothèque Internet pour Ruby conçue pour gérer la génération de courriels, l'analyse et l'envoi de manière simple et rubyesque.
Le but de cette bibliothèque est de fournir un seul point d'accès pour gérer toutes les fonctions de messagerie, y compris l'envoi et la réception des e-mails. Toutes les actions de type de réseau sont effectuées via des méthodes proxy sur net :: smtp, net :: POP3 etc.
Construit à partir de mon expérience avec TMAIL, il est conçu pour être une implémentation de rubis pure qui rend la génération, l'envoi et l'analyse de l'e-mail une évidence.
Il est également conçu à partir de zéro pour travailler avec les versions les plus modernes de Ruby. Les rubis modernes gèrent les encodages de texte beaucoup plus merveilleusement qu'auparavant, donc ces fonctionnalités ont été pleinement profitées dans cette bibliothèque permettant au courrier de gérer beaucoup plus de messages plus propres que TMAIL.
Enfin, le courrier a été conçu avec un système d'objet très simple qui ouvre vraiment les e-mails que vous analysez, si vous savez ce que vous faites, vous pouvez jouer avec chaque dernier morceau de votre e-mail directement.
Oui, toi! Le courrier est utilisé dans d'innombrables applications par des personnes du monde entier. C'est, comme tous les logiciels open source, un travail d'amour né de notre temps libre. Si vous souhaitez dire merci, creusez et contribuez à nos côtés! Triage et résoudre les problèmes de GitHub, améliorer notre documentation, ajouter de nouvelles fonctionnalités - à vous! Merci d'avoir interrompu.
Le courrier est testé contre:
Au fur et à mesure que les nouvelles versions de Ruby sont publiées, le courrier sera compatible avec la prise en charge de la "prévisualisation" et de toutes les "maintenance normale", de la "maintenance de sécurité" et des deux versions "de fin de vie" les plus récentes répertoriées sur la page des branches de maintenance Ruby. Les demandes de traction pour aider à ajouter la prise en charge des nouvelles versions de prévisualisation sont plus que bienvenues.
Chaque engagement de courrier est testé par des actions GitHub sur toutes les versions Ruby prises en charge.
Si vous souhaitez discuter du courrier avec des individus partageant les mêmes idées, veuillez vous abonner au groupe Google.
Le courrier est conforme RFC5322 et RFC6532 maintenant, c'est-à-dire qu'il peut analyser les e-mails US-ASCII et UTF-8 et générer un e-mail US-ASCII. Il y a quelques syntaxes par e-mail obsolète avec lesquels il aura des problèmes, mais il est également assez robuste, ce qui signifie que, s'il trouve quelque chose qu'il ne comprend pas, il ne se bloquera pas, il sautera le problème et maintiendra l'analyse. Dans le cas d'un en-tête qu'il ne comprend pas, il initialise l'en-tête comme un champ non structuré facultatif et continuera l'analyse.
Cela signifie que le courrier ne grobera pas (jamais) vos données (je pense).
Vous pouvez également créer des e-mails MIME. Il existe des méthodes d'aide pour faire un e-mail multipar / alternative pour le texte / simple et le texte / HTML (la paire la plus courante) et vous pouvez créer manuellement tout autre type d'e-mail MIME.
Next todo:
Fondamentalement ... nous faisons BDD par courrier. Aucune méthode n'est écrite par courrier sans spécifications correspondantes ou de couvrage. Nous nous attendons à une couverture minimale de 100% mesurée par RCOV. Bien que ce ne soit pas parfait, c'est assez bon. De plus, tous les tests fonctionnels de TMail passent avant la libération du gemme.
Cela signifie également que vous pouvez être sûr que le courrier se comportera correctement.
Vous pouvez exécuter des tests localement en exécutant bundle exec rspec
.
Vous pouvez exécuter des tests sur toutes les versions Ruby prises en charge en utilisant ACT.
Aucune API ne retire dans une version à un seul point. Tous les déménagements à déconcerter avec des avertissements pour au moins une libération de points mineurs avant le retrait.
De plus, toutes les méthodes privées ou protégées à déclarer comme telles - bien que ce soit toujours i / p.
L'installation est assez simple, j'héberge du courrier sur RubyGems, donc vous pouvez simplement faire:
# gem install mail
Si vous ne le saviez pas, la gestion des encodages dans les e-mails n'est pas aussi simple que vous l'espérez.
J'ai essayé de le simplifier:
Tous les objets qui peuvent rendre un e-mail ont une méthode #encoded
. Encodé renverra l'objet en tant que chaîne complète prête à envoyer le système de messagerie, c'est-à-dire qu'il comprendra le champ d'en-tête et la valeur et le CRLF à la fin et enveloppés au besoin.
Tous les objets qui peuvent rendre un e-mail ont une méthode #decoded
. Decoded renverra la "valeur" de l'objet uniquement en tant que chaîne. Cela signifie qu'il n'inclura pas les champs d'en-tête (comme «à:« ou «sujet»).
Par défaut, appeler #to_s
sur un objet conteneur appellera sa méthode codée, tandis que #to_s
sur un objet de champ appellera sa méthode décodée. Ainsi, l'appel #to_s
sur un objet mail renverra le courrier, tous encodés prêts à envoyer, tout en appelant #to_s
sur le champ depuis ou le corps renverra la valeur décodée de l'objet. L'objet d'en-tête du courrier est considéré comme un conteneur. Si vous êtes en doute, appelez #encoded
ou #decoded
explicitement, cela est plus sûr si vous n'êtes pas sûr.
Les champs structurés qui ont des valeurs de paramètres qui peuvent être codés (par exemple le type de contenu) fourniront des valeurs de paramètres décodées lorsque vous appelez les noms de paramètres comme méthodes contre l'objet.
Les champs structurés qui ont des valeurs de paramètres qui peuvent être codés (par exemple le type de contenu) fourniront des valeurs de paramètres codées lorsque vous appelez les noms de paramètres via l'appel de méthode object.parameters['<parameter_name>']
.
S'il vous plaît! La contribution est facile dans le courrier. Veuillez lire le document contribution.md pour plus d'informations.
Toutes les principales fonctions de messagerie devraient pouvoir se produire à partir du module de messagerie. Ainsi, vous devriez pouvoir simplement require 'mail'
pour commencer.
mail
est assez bien documenté dans son code Ruby. Vous pouvez le chercher, par exemple sur 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
Le courrier ajoutera automatiquement un champ Message-ID s'il est manquant et lui donnera un ID de message aléatoire unique et aléatoire dans le sens de:
mail = Mail . new do
to '[email protected]'
message_id '<[email protected]>'
body 'Some simple body'
end
mail . to_s =~ /Message - ID: <[email protected]>/ #=> 27
Le courrier prendra le message_id que vous attribuez à lui en faisant confiance que vous savez ce que vous faites.
Le courrier par défaut est envoyé via SMTP au port d'hôte local 25. Si vous avez un démon Sendmail ou Postfix en cours d'exécution sur ce port, l'envoi d'e-mail est aussi simple que:
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
ou
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!
L'envoi via Sendmail peut être fait comme ainsi:
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
Envoi via SMTP (par exemple à MailCatcher)
Mail . defaults do
delivery_method :smtp , address : "localhost" , port : 1025
end
EXIM nécessite son propre responsable de la livraison et peut être utilisé comme tel:
mail . delivery_method :exim , :location => "/usr/bin/exim"
mail . deliver
Le courrier peut également être «livré» à un fichier de journaux pour le développement et les tests:
# 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
Vous pouvez configurer le courrier pour recevoir un e-mail à l'aide de retriever_method
dans Mail.defaults
:
# 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
Vous pouvez accéder à des e-mails entrants de plusieurs façons.
L'email le plus récent:
Mail . all #=> Returns an array of all emails
Mail . first #=> Returns the first unread email
Mail . last #=> Returns the last unread email
Les 10 premiers e-mails triés par date dans l'ordre croissant:
emails = Mail . find ( :what => :first , :count => 10 , :order => :asc )
emails . length #=> 10
Ou même tous les e-mails:
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...
Beaucoup plus de méthodes disponibles.
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'}
Le courrier génère un arbre de pièces. Chaque message a plusieurs ou pas de pièces. Chaque partie est un autre message qui peut avoir plusieurs ou pas de pièces.
Un message n'aura des pièces que s'il s'agit d'un type de contenu multiparte / mixte ou multipart / associé et a une limite définie.
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
Le courrier fait des hypothèses de base et rend la chose commune aussi simple que possible ... (demander beaucoup à une bibliothèque de courrier)
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
Le courrier livre ensuite l'e-mail à la fin du bloc et renvoie l'objet Message :: Message résultant, que vous pouvez ensuite inspecter si vous le souhaitez ...
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--
Le courrier insère le codage de transfert de contenu, la version MIME, le contenu-ids et gère le type de contenu et la limite.
Le courrier suppose que si votre texte dans le corps n'est que US-ASCII, votre codage de transfert est 7 bits et il est texte / simple. Vous pouvez remplacer cela en le déclarant explicitement.
Vous n'avez pas à utiliser un bloc avec le texte et la pièce HTML inclus, vous pouvez simplement le faire de manière déclarative. Cependant, vous devez ajouter du courrier :: des pièces à un e-mail, pas par courrier :: messages.
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
Entraîne le même e-mail que fait en utilisant le formulaire de bloc
@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
Vous pouvez simplement lire le fichier sur un chemin absolu, le courrier essaiera de deviner le MIME_TYPE et codera le fichier dans Base64 pour vous.
@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
Ou vous pouvez passer dans file_data et lui donner un nom de fichier, encore une fois, le courrier essaiera de deviner le MIME_TYPE pour vous.
@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
Vous pouvez également remplacer le type de média MIME deviné si vous savez vraiment mieux que le courrier (cela devrait être rarement nécessaire)
@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'
Bien sûr ... le courrier va aussi aller à un accessoire
@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'
Voir «Tester et extraire les pièces jointes» ci-dessus pour plus de détails.
Si le courrier fait partie de votre système, vous aurez besoin d'un moyen de le tester sans envoyer de courriels, le TestMailer peut le faire pour vous.
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
=> [ ]
Il y a aussi un ensemble de Matchs RSPEC volés / inspirés par les matchs d'action d'action d'Haula (vous voudrez définir delivery_method
comme ci-dessus aussi):
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
Les fichiers de luminaires de spécifications dans Spec / Fixtures / Emails / FROM_TREC_2005 proviennent du TREC Public Spam Corpus 2005. Ils restent protégés par le droit d'auteur en vertu des termes de ce projet et de ce contrat de licence. Ils sont utilisés dans ce projet pour vérifier et décrire le développement de cette mise en œuvre de l'analyseur par e-mail.
http://plg.uwaterloo.ca/~gvcormac/treccorpus/
Ils sont utilisés comme autorisé par les «utilisations autorisées, clause 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/
(La licence MIT)
Copyright (C) 2009-2016 Mikel Lindsaar
L'autorisation est accordée gratuitement par la présente à toute personne qui obtient une copie de ce logiciel et des fichiers de documentation associés (le `` logiciel ''), pour traiter le logiciel sans restriction, y compris sans limiter les droits d'utilisation, de copier, de modifier, de fusionner , publier, distribuer, sous-licencier et / ou vendre des copies du logiciel, et pour permettre aux personnes à qui le logiciel est fourni pour le faire, sous réserve des conditions suivantes:
L'avis de droit d'auteur ci-dessus et le présent avis d'autorisation sont inclus dans toutes les copies ou des parties substantielles du logiciel.
Le logiciel est fourni «tel quel», sans garantie d'aucune sorte, express ou implicite, y compris, mais sans s'y limiter, les garanties de qualité marchande, d'adéquation à un usage particulier et de non-contrefaçon. En aucun cas, les auteurs ou les titulaires de droits d'auteur ne seront pas responsables de toute réclamation, dommage ou autre responsabilité, que ce soit dans une action de contrat, de délit ou autre, découlant de, hors du logiciel ou de l'utilisation ou d'autres transactions dans le LOGICIEL.