Mail es una biblioteca de Internet para Ruby que está diseñada para manejar la generación de correo electrónico, el análisis y el envío de una manera simple y rubí.
El propósito de esta biblioteca es proporcionar un solo punto de acceso para manejar todas las funciones de correo electrónico, incluido el envío y la recepción del correo electrónico. Todas las acciones de tipo de red se realizan a través de métodos proxy para net :: smtp, net :: pop3 etc.
Construido a partir de mi experiencia con Tmail, está diseñado para ser una implementación pura de Ruby que hace que generar, enviar y analizar el correo electrónico sea obvio.
También está diseñado desde cero para trabajar con las versiones más modernas de Ruby. Los rubíes modernos manejan las codificaciones de texto mucho más maravillosamente que antes, por lo que estas características se han aprovechado en su máximo valor en esta biblioteca, lo que permite que el correo maneje muchos más mensajes más limpiamente que Tmail.
Finalmente, Mail ha sido diseñado con un sistema orientado a objetos muy simple que realmente abre los mensajes de correo electrónico que está analizando, si sabe lo que está haciendo, puede jugar con el juguete hasta el último bit de su correo electrónico directamente.
¡Sí, tú! El correo se utiliza en innumerables aplicaciones de personas de todo el mundo. Es, como todo el software de código abierto, un trabajo de amor que lleva desde nuestro tiempo libre. Si desea agradecer, ¡excave y contribuya junto a nosotros! Triaje y solucione problemas de GitHub, mejore nuestra documentación, agregue nuevas características, ¡hasta usted! Gracias por lanzar.
El correo se prueba contra:
A medida que se lanzan nuevas versiones de Ruby, el correo será compatible con el soporte para la "vista previa" y todo el "mantenimiento normal", el "mantenimiento de la seguridad" y las dos versiones más recientes de "fin de vida" que se enumeran en la página de ramas de mantenimiento de Ruby. Las solicitudes de extracción para ayudar a agregar soporte para nuevos lanzamientos de vista previa son más que bienvenidas.
Cada confirmación de correo es probada por las acciones de GitHub en todas las versiones de Ruby compatibles.
Si desea discutir el correo con personas con ideas afines, suscríbase al Grupo de Google.
El correo electrónico cumple con RFC5322 y RFC6532 ahora, es decir, puede analizar el correo electrónico de US-ASCII y UTF-8 y generar el correo electrónico de US-ASCII. Hay algunas sintaxis de correo electrónico obsoleta con la que tendrá problemas, pero también es bastante robusto, lo que significa que si encuentra algo, no entiende que no se bloqueará, en su lugar, saltará el problema y seguirá analizando. En el caso de un encabezado que no comprende, inicializará el encabezado como un campo no estructurado opcional y continuará analizando.
Esto significa que el correo no (nunca) crujirá sus datos (creo).
También puede crear correos electrónicos de MIME. Existen métodos ayudantes para hacer un correo electrónico multipart/alternativo para texto/simple y texto/html (el par más común) y puede crear manualmente cualquier otro tipo de correo electrónico MIME.
Next ToDo:
Básicamente ... hacemos BDD por correo. Ningún método se escribe en el correo sin una especificación correspondiente o de cobertura. Esperamos como una cobertura mínima del 100% medida por RCOV. Si bien esto no es perfecto en ninguna medida, es bastante bueno. Además, todas las pruebas funcionales de Tmail se pasarán antes de que se libere la gema.
También significa que puede estar seguro de que el correo se comportará correctamente.
Puede ejecutar pruebas localmente ejecutando bundle exec rspec
.
Puede ejecutar pruebas en todas las versiones de Ruby compatibles utilizando ACT.
No hay removías API dentro de una versión de un solo punto. Todas las mudanzas estarán en desorden con advertencias para al menos una liberación de puntos menores antes de la eliminación.
Además, todos los métodos privados o protegidos para ser declarados como tales, aunque todavía es I/P.
La instalación es bastante simple, anfigo el correo en Rubygems, por lo que puede hacer:
# gem install mail
Si no lo supiera, manejar codificaciones en correos electrónicos no es tan sencillo como esperaría.
He intentado simplificarlo un poco:
Todos los objetos que pueden transmitir un correo electrónico, tienen un método #encoded
. Encoded devolverá el objeto como una cadena completa lista para enviar el sistema de correo, es decir, incluirá el campo y el valor del encabezado y CRLF al final y envuelto según sea necesario.
Todos los objetos que pueden transmitir un correo electrónico, tienen un método #decoded
. Decoded devolverá el "valor" del objeto solo como una cadena. Esto significa que no incluirá los campos de encabezado (como 'para:' o 'sujeto:').
De forma predeterminada, llamar #to_s
en un objeto contenedor llamará a su método codificado, mientras que #to_s
en un objeto de campo llamará a su método decodificado. Por lo tanto, llamar #to_s
en un objeto de correo devolverá el correo, todo codificado listo para enviar, mientras llamará #to_s
en el campo desde el campo o el cuerpo devolverá el valor decodificado del objeto. El objeto de encabezado del correo se considera un contenedor. Si tiene dudas, llame #encoded
o #decoded
Explicitly, esto es más seguro si no está seguro.
Los campos estructurados que tienen valores de parámetros que se pueden codificar (por ejemplo, tipo de contenido) proporcionarán valores de parámetros decodificados cuando llame a los nombres de los parámetros como métodos contra el objeto.
Los campos estructurados que tienen valores de parámetros que se pueden codificar (por ejemplo, tipo de contenido) proporcionarán valores de parámetros codificados cuando llame a los nombres de los parámetros a través de la llamada del método object.parameters['<parameter_name>']
.
¡Por favor hazlo! Contribuir es fácil en el correo. Lea el documento Contributing.MD para obtener más información.
Todas las funciones principales de correo deberían poder ocurrir desde el módulo de correo. Por lo tanto, debería poder require 'mail'
para comenzar.
mail
está bastante bien documentado en su código Ruby. Puedes buscarlo, por ejemplo, en 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
El correo agregará automáticamente un campo de ID de mensaje si falta y le dará un ID de mensaje único y aleatorio en la línea 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
El correo tomará el mensaje_id que le asigne a él confiando que sabe lo que está haciendo.
El correo electrónico es envío a través de SMTP al puerto de host local 25. Si tiene un demonio SendMail o Postfix que se ejecuta en este puerto, enviar correo electrónico es tan fácil como:
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
o
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!
Enviar a través de Sendmail se puede hacer así:
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
Envío a través de SMTP (por ejemplo a MailCatcher)
Mail . defaults do
delivery_method :smtp , address : "localhost" , port : 1025
end
EXIM requiere su propio gerente de entrega, y se puede usar así:
mail . delivery_method :exim , :location => "/usr/bin/exim"
mail . deliver
El correo también puede ser "entregado" a un archivo de registro para el desarrollo y las pruebas:
# 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
Puede configurar el correo para recibir correo electrónico utilizando retriever_method
dentro de 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
Puede acceder al correo electrónico entrante de varias maneras.
El correo electrónico más reciente:
Mail . all #=> Returns an array of all emails
Mail . first #=> Returns the first unread email
Mail . last #=> Returns the last unread email
Los primeros 10 correos electrónicos ordenados por fecha en orden ascendente:
emails = Mail . find ( :what => :first , :count => 10 , :order => :asc )
emails . length #=> 10
O incluso todos los correos electrónicos:
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...
Muchos más métodos 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'}
El correo genera un árbol de piezas. Cada mensaje tiene muchas o ninguna parte. Cada parte es otro mensaje que puede tener muchas o ninguna parte.
Un mensaje solo tendrá piezas si es un tipo de contenido multipart/mixto o multipart/relacionado y tiene un límite definido.
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
El correo hace algunos supuestos básicos y hace que hacer lo común lo sea lo más simple posible ... (preguntando mucho desde una biblioteca de correo)
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
Correo luego entrega el correo electrónico al final del bloque y devuelve el objeto de mensaje de correo resultante, que luego puede inspeccionar si así lo desea ...
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--
El correo inserta la codificación de transferencia de contenido, la versión MIME, el ID de contenido y maneja el tipo de contenido y el límite.
El correo supone que si su texto en el cuerpo es solo US-ASCII, que su codificación de transferencia es de 7 bits y es texto/simple. Puede anular esto declarándolo explícitamente.
No tiene que usar un bloque con el texto y la parte HTML incluida, puede hacerlo declarativamente. Sin embargo, debe agregar Mail :: Parts a un correo electrónico, no Morse :: Mensajes.
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
Resulta en el mismo correo electrónico que se hace utilizando el formulario de bloque
@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
Puede leer el archivo en una ruta absoluta, el correo intentará adivinar el mime_type y codificará el archivo en base64 para usted.
@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
O puede pasar en file_data y darle un nombre de archivo, nuevamente, el correo intentará adivinar el mime_type para usted.
@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
También puede anular el tipo de medios MIME adivinado si realmente sabe mejor que el correo (esto rara vez se necesita)
@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'
Por supuesto ... el correo también se remonta un archivo adjunto
@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'
Consulte "Prueba y extracción de archivos adjuntos" anteriormente para obtener más detalles.
Si el correo es parte de su sistema, necesitará una forma de probarlo sin enviar correos electrónicos, el TestMailer puede hacerlo por usted.
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
=> [ ]
También hay un conjunto de Rspec Matchers robados/inspirados en ActionMailer Matchers de Arrbase (querrá establecer entrega delivery_method
como anteriormente):
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
Los archivos de accesorio de especificaciones en Spec/Fixtures/Correos electrónicos/From_trec_2005 son del Corpus de spam público TREC 2005. Siguen con derechos de autor bajo los términos de ese proyecto y acuerdo de licencia. Se utilizan en este proyecto para verificar y describir el desarrollo de esta implementación de analizador de correo electrónico.
http://plg.uwaterloo.ca/~gvcormac/treccorpus/
Se usan según lo permitido por 'usos permitidos, cláusula 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 licencia del MIT)
Copyright (c) 2009-2016 Mikel Lindsaar
Por la presente, se otorga el permiso, de forma gratuita, a cualquier persona que obtenga una copia de este software y archivos de documentación asociados (el 'software'), para tratar el software sin restricción, incluidos los derechos de usar, copiar, modificar, modificar, modificar, fusionar , publique, distribuya, sublicence y venda copias del software, y para permitir a las personas a las que se proporciona el software para hacerlo, sujeto a las siguientes condiciones:
El aviso de derechos de autor anterior y este aviso de permiso se incluirán en todas las copias o porciones sustanciales del software.
El software se proporciona 'tal cual', sin garantía de ningún tipo, expresa o implícita, incluidas, entre otros, las garantías de comerciabilidad, idoneidad para un propósito particular y no infracción. En ningún caso los autores o titulares de derechos de autor serán responsables de cualquier reclamo, daños u otro responsabilidad, ya sea en una acción de contrato, agravio o de otro tipo, derivado, de o en relación con el software o el uso u otros tratos en el SOFTWARE.