1 ¿Qué es Action Mailbox?
Action Mailbox enruta los correos electrónicos entrantes a buzones similares a controladores para su procesamiento en su aplicación Rails. Action Mailbox es para recibir correos electrónicos, mientras que Action Mailer es para enviarlos.
Los correos electrónicos entrantes se enrutan de manera asincrónica usando Active Job a uno o varios buzones dedicados. Estos correos electrónicos se convierten en registros de InboundEmail
usando Active Record, que son capaces de interactuar directamente con el resto de su modelo de dominio.
Los registros de InboundEmail
también proporcionan seguimiento del ciclo de vida, almacenamiento del correo electrónico original a través de Active Storage y manejo responsable de datos con incineración activada por defecto.
Action Mailbox incluye ingresses que permiten a su aplicación recibir correos electrónicos de proveedores externos como Mailgun, Mandrill, Postmark y SendGrid. También puede manejar correos electrónicos entrantes directamente a través de los ingresses integrados de Exim, Postfix y Qmail.
2 Configuración
Action Mailbox tiene varias partes móviles. Primero, ejecutará el instalador. Luego, elegirá y configurará un ingreso para manejar el correo electrónico entrante. Después estará listo para agregar el enrutamiento de Action Mailbox, crear buzones y comenzar a procesar correos electrónicos entrantes.
Para comenzar, instalemos Action Mailbox:
$ bin/rails action_mailbox:install
Esto creará un archivo application_mailbox.rb
y copiará las migraciones.
$ bin/rails db:migrate
Esto ejecutará las migraciones de Action Mailbox y Active Storage.
La tabla de Action Mailbox action_mailbox_inbound_emails
almacena mensajes entrantes y su estado de procesamiento.
En este punto, puede iniciar su servidor Rails y visitar http://localhost:3000/rails/conductor/action_mailbox/inbound_emails
. Consulte Desarrollo Local y Pruebas para más información.
El siguiente paso es configurar un ingreso en su aplicación Rails para especificar cómo deben recibirse los correos electrónicos entrantes.
3 Configuración de Ingreso
Configurar el ingreso implica establecer credenciales e información de endpoint para el servicio de correo electrónico elegido. Aquí están los pasos para cada uno de los ingresos soportados.
3.1 Exim
Indique a Action Mailbox que acepte correos electrónicos de un relay SMTP:
# config/environments/production.rb
config.action_mailbox.ingress = :relay
Genere una contraseña fuerte que Action Mailbox pueda usar para autenticar solicitudes al ingreso relay.
Use bin/rails credentials:edit
para agregar la contraseña a las credenciales cifradas de su aplicación bajo action_mailbox.ingress_password
, donde Action Mailbox la encontrará automáticamente:
action_mailbox:
ingress_password: ...
Alternativamente, proporcione la contraseña en la variable de entorno RAILS_INBOUND_EMAIL_PASSWORD
.
Configure Exim para canalizar correos electrónicos entrantes a bin/rails action_mailbox:ingress:exim
, proporcionando la URL
del ingreso relay y la INGRESS_PASSWORD
que generó anteriormente. Si su aplicación estuviera en https://example.com
, el comando completo se vería así:
$ bin/rails action_mailbox:ingress:exim URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=...
3.2 Mailgun
Proporcione a Action Mailbox su clave de firma de Mailgun (que puede encontrar en Configuración -> Seguridad y Usuarios -> Seguridad de API en Mailgun), para que pueda autenticar solicitudes al ingreso de Mailgun.
Use bin/rails credentials:edit
para agregar su clave de firma a las credenciales cifradas de su aplicación bajo action_mailbox.mailgun_signing_key
, donde Action Mailbox la encontrará automáticamente:
action_mailbox:
mailgun_signing_key: ...
Alternativamente, proporcione su clave de firma en la variable de entorno MAILGUN_INGRESS_SIGNING_KEY
.
Indique a Action Mailbox que acepte correos electrónicos de Mailgun:
# config/environments/production.rb
config.action_mailbox.ingress = :mailgun
Configure Mailgun para reenviar correos electrónicos entrantes a /rails/action_mailbox/mailgun/inbound_emails/mime
. Si su aplicación estuviera en https://example.com
, especificaría la URL completamente calificada https://example.com/rails/action_mailbox/mailgun/inbound_emails/mime
.
3.3 Mandrill
Proporcione a Action Mailbox su clave API de Mandrill, para que pueda autenticar solicitudes al ingreso de Mandrill.
Use bin/rails credentials:edit
para agregar su clave API a las credenciales cifradas de su aplicación bajo action_mailbox.mandrill_api_key
, donde Action Mailbox la encontrará automáticamente:
action_mailbox:
mandrill_api_key: ...
Alternativamente, proporcione su clave API en la variable de entorno MANDRILL_INGRESS_API_KEY
.
Indique a Action Mailbox que acepte correos electrónicos de Mandrill:
# config/environments/production.rb
config.action_mailbox.ingress = :mandrill
Configure Mandrill para enrutar correos electrónicos entrantes a /rails/action_mailbox/mandrill/inbound_emails
. Si su aplicación estuviera en https://example.com
, especificaría la URL completamente calificada https://example.com/rails/action_mailbox/mandrill/inbound_emails
.
3.4 Postfix
Indique a Action Mailbox que acepte correos electrónicos de un relay SMTP:
# config/environments/production.rb
config.action_mailbox.ingress = :relay
Genere una contraseña fuerte que Action Mailbox pueda usar para autenticar solicitudes al ingreso relay.
Use bin/rails credentials:edit
para agregar la contraseña a las credenciales cifradas de su aplicación bajo action_mailbox.ingress_password
, donde Action Mailbox la encontrará automáticamente:
action_mailbox:
ingress_password: ...
Alternativamente, proporcione la contraseña en la variable de entorno RAILS_INBOUND_EMAIL_PASSWORD
.
Configure Postfix para canalizar correos electrónicos entrantes a bin/rails action_mailbox:ingress:postfix
, proporcionando la URL
del ingreso de Postfix y la INGRESS_PASSWORD
que generó anteriormente. Si su aplicación estuviera en https://example.com
, el comando completo se vería así:
$ bin/rails action_mailbox:ingress:postfix URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=...
3.5 Postmark
Indique a Action Mailbox que acepte correos electrónicos de Postmark:
# config/environments/production.rb
config.action_mailbox.ingress = :postmark
Genere una contraseña fuerte que Action Mailbox pueda usar para autenticar solicitudes al ingreso de Postmark.
Use bin/rails credentials:edit
para agregar la contraseña a las credenciales cifradas de su aplicación bajo action_mailbox.ingress_password
, donde Action Mailbox la encontrará automáticamente:
action_mailbox:
ingress_password: ...
Alternativamente, proporcione la contraseña en la variable de entorno RAILS_INBOUND_EMAIL_PASSWORD
.
Configure el webhook de entrada de Postmark para reenviar correos electrónicos entrantes a /rails/action_mailbox/postmark/inbound_emails
con el nombre de usuario actionmailbox
y la contraseña que generó anteriormente. Si su aplicación estuviera en https://example.com
, configuraría Postmark con la siguiente URL completamente calificada:
https://actionmailbox:PASSWORD@example.com/rails/action_mailbox/postmark/inbound_emails
NOTA: Al configurar su webhook de entrada de Postmark, asegúrese de marcar la casilla etiquetada "Incluir contenido de correo electrónico sin procesar en la carga útil JSON". Action Mailbox necesita el contenido del correo electrónico sin procesar para funcionar.
3.6 Qmail
Indique a Action Mailbox que acepte correos electrónicos de un relay SMTP:
# config/environments/production.rb
config.action_mailbox.ingress = :relay
Genere una contraseña fuerte que Action Mailbox pueda usar para autenticar solicitudes al ingreso relay.
Use bin/rails credentials:edit
para agregar la contraseña a las credenciales cifradas de su aplicación bajo action_mailbox.ingress_password
, donde Action Mailbox la encontrará automáticamente:
action_mailbox:
ingress_password: ...
Alternativamente, proporcione la contraseña en la variable de entorno RAILS_INBOUND_EMAIL_PASSWORD
.
Configure Qmail para canalizar correos electrónicos entrantes a bin/rails action_mailbox:ingress:qmail
, proporcionando la URL
del ingreso relay y la INGRESS_PASSWORD
que generó anteriormente. Si su aplicación estuviera en https://example.com
, el comando completo se vería así:
$ bin/rails action_mailbox:ingress:qmail URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=...
3.7 SendGrid
Indique a Action Mailbox que acepte correos electrónicos de SendGrid:
# config/environments/production.rb
config.action_mailbox.ingress = :sendgrid
Genere una contraseña fuerte que Action Mailbox pueda usar para autenticar solicitudes al ingreso de SendGrid.
Use bin/rails credentials:edit
para agregar la contraseña a las credenciales cifradas de su aplicación bajo action_mailbox.ingress_password
, donde Action Mailbox la encontrará automáticamente:
action_mailbox:
ingress_password: ...
Alternativamente, proporcione la contraseña en la variable de entorno RAILS_INBOUND_EMAIL_PASSWORD
.
Configure SendGrid Inbound Parse para reenviar correos electrónicos entrantes a /rails/action_mailbox/sendgrid/inbound_emails
con el nombre de usuario actionmailbox
y la contraseña que generó anteriormente. Si su aplicación estuviera en https://example.com
, configuraría SendGrid con la siguiente URL:
https://actionmailbox:PASSWORD@example.com/rails/action_mailbox/sendgrid/inbound_emails
NOTA: Al configurar su webhook de SendGrid Inbound Parse, asegúrese de marcar la casilla etiquetada “Publicar el mensaje MIME completo y sin procesar.” Action Mailbox necesita el mensaje MIME sin procesar para funcionar.
4 Procesamiento de Correos Electrónicos Entrantes
El procesamiento de correos electrónicos entrantes generalmente implica usar el contenido del correo electrónico para crear modelos, actualizar vistas, poner en cola trabajo en segundo plano, etc., en su aplicación Rails.
Antes de que pueda comenzar a procesar correos electrónicos entrantes, deberá configurar el enrutamiento de Action Mailbox y crear buzones.
4.1 Configurar Enrutamiento
Después de que un correo electrónico entrante se recibe a través del ingreso configurado, necesita ser enviado a un buzón para su procesamiento real por su aplicación. Al igual que el enrutador de Rails que despacha URLs a controladores, el enrutamiento en Action Mailbox define qué correos electrónicos van a qué buzones para su procesamiento. Las rutas se agregan al archivo application_mailbox.rb
usando expresiones regulares:
# app/mailboxes/application_mailbox.rb
class ApplicationMailbox < ActionMailbox::Base
routing(/^save@/i => :forwards)
routing(/@replies\./i => :replies)
end
La expresión regular coincide con los campos to
, cc
o bcc
del correo electrónico entrante. Por ejemplo, lo anterior coincidirá con cualquier correo electrónico enviado a save@
a un buzón "forwards". Hay otras formas de enrutar un correo electrónico, consulte ActionMailbox::Base
para más información.
Necesitamos crear ese buzón "forwards" a continuación.
4.2 Crear un Buzón
# Generar nuevo buzón
$ bin/rails generate mailbox forwards
Esto crea app/mailboxes/forwards_mailbox.rb
, con una clase ForwardsMailbox
y un método process
.
4.3 Procesar Correo Electrónico
Al procesar un InboundEmail
, puede obtener la versión analizada del correo electrónico como un objeto Mail
con InboundEmail#mail
. También puede obtener la fuente sin procesar directamente usando el método #source
. Con el objeto Mail
, puede acceder a los campos relevantes, como mail.to
, mail.body.decoded
, etc.
irb> mail
=> #<Mail::Message:33780, Multipart: false, Headers: <Date: Wed, 31 Jan 2024 22:18:40 -0600>, <From: someone@hey.com>, <To: save@example.com>, <Message-ID: <65bb1ba066830_50303a70397e@Bhumis-MacBook-Pro.local.mail>>, <In-Reply-To: >, <Subject: Hello Action Mailbox>, <Mime-Version: 1.0>, <Content-Type: text/plain; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>, <x-original-to: >>
irb> mail.to
=> ["save@example.com"]
irb> mail.from
=> ["someone@hey.com"]
irb> mail.date
=> Wed, 31 Jan 2024 22:18:40 -0600
irb> mail.subject
=> "Hello Action Mailbox"
irb> mail.body.decoded
=> "This is the body of the email message."
# mail.decoded, una abreviatura de mail.body.decoded, también funciona
irb> mail.decoded
=> "This is the body of the email message."
irb> mail.body
=> <Mail::Body:0x00007fc74cbf46c0 @boundary=nil, @preamble=nil, @epilogue=nil, @charset="US-ASCII", @part_sort_order=["text/plain", "text/enriched", "text/html", "multipart/alternative"], @parts=[], @raw_source="This is the body of the email message.", @ascii_only=true, @encoding="7bit">
4.4 Estado del Correo Electrónico Entrante
Mientras el correo electrónico se enruta a un buzón coincidente y se procesa, Action Mailbox actualiza el estado del correo electrónico almacenado en la tabla action_mailbox_inbound_emails
con uno de los siguientes valores:
pending
: Recibido por uno de los controladores de ingreso y programado para enrutamiento.processing
: Durante el procesamiento activo, mientras un buzón específico ejecuta su métodoprocess
.delivered
: Procesado con éxito por el buzón específico.failed
: Se produjo una excepción durante la ejecución del métodoprocess
del buzón específico.bounced
: Rechazado para procesamiento por el buzón específico y devuelto al remitente.
Si el correo electrónico está marcado como delivered
, failed
o bounced
, se considera "procesado" y se marca para incineración.
5 Ejemplo
Aquí hay un ejemplo de un Action Mailbox que procesa correos electrónicos para crear "forwards" para el proyecto del usuario.
El callback before_processing
se utiliza para asegurar que se cumplan ciertas condiciones antes de que se llame al método process
. En este caso, before_processing
verifica que el usuario tenga al menos un proyecto. Otros callbacks soportados por Action Mailbox son after_processing
y around_processing
.
El correo electrónico puede ser devuelto usando bounced_with
si el "forwarder" no tiene proyectos. El "forwarder" es un User
con el mismo correo electrónico que mail.from
.
Si el "forwarder" tiene al menos un proyecto, el método record_forward
crea un modelo de Active Record en la aplicación usando los datos del correo electrónico mail.subject
y mail.decoded
. De lo contrario, envía un correo electrónico, usando Action Mailer, solicitando al "forwarder" que elija un proyecto.
# app/mailboxes/forwards_mailbox.rb
class ForwardsMailbox < ApplicationMailbox
# Los callbacks especifican requisitos previos para el procesamiento
before_processing :require_projects
def process
# Registrar el forward en el único proyecto, o…
if forwarder.projects.one?
record_forward
else
# …involucrar un segundo Action Mailer para preguntar en qué proyecto reenviar.
request_forwarding_project
end
end
private
def require_projects
if forwarder.projects.none?
# Use Action Mailers para devolver correos electrónicos entrantes al remitente: esto detiene el procesamiento
bounce_with Forwards::BounceMailer.no_projects(inbound_email, forwarder: forwarder)
end
end
def record_forward
forwarder.forwards.create subject: mail.subject, content: mail.decoded
end
def request_forwarding_project
Forwards::RoutingMailer.choose_project(inbound_email, forwarder: forwarder).deliver_now
end
def forwarder
@forwarder ||= User.find_by(email_address: mail.from)
end
end
6 Desarrollo Local y Pruebas
Es útil poder probar correos electrónicos entrantes en desarrollo sin realmente enviar y recibir correos electrónicos reales. Para lograr esto, hay un controlador de conductor montado en /rails/conductor/action_mailbox/inbound_emails
, que le da un índice de todos los InboundEmails en el sistema, su estado de procesamiento y un formulario para crear un nuevo InboundEmail también.
Aquí hay un ejemplo de prueba de un correo electrónico entrante con Action Mailbox TestHelpers.
class ForwardsMailboxTest < ActionMailbox::TestCase
test "registrar directamente un forward de cliente para un forwarder y un forwardee correspondiente a un proyecto" do
assert_difference -> { people(:david).buckets.first.recordings.count } do
receive_inbound_email_from_mail \
to: 'save@example.com',
from: people(:david).email_address,
subject: "Fwd: Status update?",
body: <<~BODY
--- Begin forwarded message ---
From: Frank Holland <frank@microsoft.com>
What's the status?
BODY
end
recording = people(:david).buckets.first.recordings.last
assert_equal people(:david), recording.creator
assert_equal "Status update?", recording.forward.subject
assert_match "What's the status?", recording.forward.content.to_s
end
end
Por favor, consulte la API de ActionMailbox::TestHelper para obtener más métodos de ayuda para pruebas.
7 Incineración de InboundEmails
Por defecto, un InboundEmail
que ha sido procesado será incinerado después de 30 días. El InboundEmail
se considera procesado cuando su estado cambia a delivered
, failed
o bounced
.
La incineración real se realiza a través del IncinerationJob
que está programado para ejecutarse después del tiempo de config.action_mailbox.incinerate_after
. Este valor está configurado en 30.days
por defecto, pero puede cambiarlo en su configuración de production.rb. (Tenga en cuenta que esta programación de incineración a futuro depende de que su cola de trabajos pueda mantener trabajos durante tanto tiempo).
La incineración de datos por defecto asegura que no está reteniendo datos de personas innecesariamente después de que puedan haber cancelado sus cuentas o eliminado su contenido.
La intención con el procesamiento de Action Mailbox es que a medida que procesa un correo electrónico, debe extraer todos los datos que necesita del correo electrónico y persistirlos en modelos de dominio en su aplicación. El InboundEmail
permanece en el sistema durante el tiempo configurado para permitir depuración y análisis forense y luego será eliminado.
Comentarios
Se te anima a ayudar a mejorar la calidad de esta guía.
Por favor contribuye si ves algún error tipográfico o errores fácticos. Para comenzar, puedes leer nuestra sección de contribuciones a la documentación.
También puedes encontrar contenido incompleto o cosas que no están actualizadas. Por favor agrega cualquier documentación faltante para main. Asegúrate de revisar Guías Edge primero para verificar si los problemas ya están resueltos o no en la rama principal. Revisa las Guías de Ruby on Rails para estilo y convenciones.
Si por alguna razón detectas algo que corregir pero no puedes hacerlo tú mismo, por favor abre un issue.
Y por último, pero no menos importante, cualquier tipo de discusión sobre la documentación de Ruby on Rails es muy bienvenida en el Foro oficial de Ruby on Rails.