Spanish (Español) translation by Elías Nicolás (you can also view the original English article)
En el artículo anterior vimos cómo podemos enviar mensajes de correo electrónico programaticamente en Drupal 8. También vimos cómo otros módulos pueden alterar estos mensajes de correo salientes. Hoy, vamos a ver cómo podemos usar la API de correo para extender este comportamiento predeterminado. El propósito es utilizar un servicio externo como un medio para la entrega de correo electrónico.
Para ello, vamos a utilizar Mandrill, aunque el enfoque del artículo no será su API o cómo trabajar con él, sino más bien el lado Drupal de las cosas. Y recuerde, el módulo de trabajo se puede encontrar en este repositorio en Git.
Como
hemos visto en el artículo anterior, el envío de un correo electrónico
en Drupal 8 ocurre solicitando el administrador de correo, pasando
algunos parámetros a su método mail()
y configurar una plantilla
dentro de una implementación hook_mail()
. Lo que
el administrador de correo hace internamente es cargar el complemento de
correo adecuado, crear el correo electrónico y, a continuación,
delegar al método mail()
cualquier plugin que se cargó.
Pero, ¿a quién se delega realmente?
Selección de complemento
Una cosa importante a entender antes de escribir nuestro propio complemento es el proceso de selección del administrador de correo para cargar complementos. En otras palabras, ¿cómo sabemos qué complemento se cargará y cómo podemos hacer que cargue el nuestro?
La array de configuración system.mail.interface
contiene todas las respuestas. Contiene
los identificadores de los complementos disponibles, marcados por el
contexto en el que se usan. Por defecto, todo lo que tenemos dentro de
esta configuración es default => phpmail
. Esto
significa que el complemento con id phpmail
(la clase PHPMail) se
utiliza como respaldo para todos los contextos que no se especifican de
otro modo, es decir, el valor predeterminado.
Si queremos escribir nuestro propio complemento, necesitamos agregar otro elemento en esa matriz con el ID de complemento como su valor. La clave para este valor puede ser una de dos cosas: el nombre de la máquina de nuestro módulo (para cargar el plugin siempre que nuestro módulo envíe mensajes de correo electrónico) o una combinación de nombre de módulo y plantilla de correo electrónico clave (para cargar el plugin siempre que nuestro módulo envía un correo electrónico Utilizando esa clave específica).
Un
ejemplo de la última construcción es d8mail_node_insert
, donde d8mail
es nuestro nombre de módulo que empezamos a construir en el artículo
anterior, y node_insert
es la clave de plantilla de correo electrónico
que definimos.
Así que
ahora que sabemos cómo ocurre la selección de complementos de correo,
debemos asegurarnos de que esta matriz de configuración contenga la
información necesaria para que los correos enviados con nuestro módulo
d8mail
usen el nuevo complemento que vamos a construir. Podemos hacer esto dentro de una implementación hook_install() que se dispara sólo una vez cuando el módulo se instala:
d8mail.install:
/** * Implements hook_install(). */ function d8mail_install() { $config = \Drupal::configFactory()->getEditable('system.mail'); $mail_plugins = $config->get('interface'); if (in_array('d8mail', array_keys($mail_plugins))) { return; } $mail_plugins['d8mail'] = 'mandrill_mail'; $config->set('interface', $mail_plugins)->save(); }
No es complicado lo que pasa arriba. Cargamos
el objeto de configuración editable que representa la configuración de
system.mail
y añadimos un nuevo elemento a la array interface
: d8mail
=> mandrill_mail
. Pronto
crearemos un plugin de correo con el id de mandrill_mail
que se
utilizará para todos los correos electrónicos enviados por el módulo
d8mail
. Y eso es todo.
Pero antes de avanzar, necesitamos asegurarnos de que este cambio se revertirá cuando el módulo se desinstale. Para ello, podemos utilizar la contrapartida hook_uninstall() que se llama cuando un módulo se desinstala (no hay más módulo de desactivación en Drupal 8).
Dentro del mismo archivo:
/** * Implements hook_uninstall(). */ function d8mail_uninstall() { $config = \Drupal::configFactory()->getEditable('system.mail'); $mail_plugins = $config->get('interface'); if ( ! in_array('d8mail', array_keys($mail_plugins))) { return; } unset($mail_plugins['d8mail']); $config->set('interface', $mail_plugins)->save(); }
Con la implementación hook_uninstall()
hacemos lo contrario de antes: eliminamos nuestro id de complemento si está configurado.
El escenario de instalación / desinstalación es solo un camino a seguir. También puede crear un formulario de administración que permita a los usuarios seleccionar el complemento que desee y en qué contexto. Pero todavía debe asegurarse de que al deshabilitar el módulo que define un complemento en particular, la configuración ya no guardará una referencia a ese complemento. De lo contrario, el administrador de correo puede tratar de utilizar una clase inexistente y lanzar todo tipo de errores.
Mandrill
Como mencioné antes, trabajaremos con la API Mandrill para ilustrar nuestra tarea. Así que vamos a cargar la Biblioteca PHP de Mandrill y hacerla disponible en nuestro entorno. Hay tres pasos que tenemos que hacer para esto.
Primero, necesitamos conseguir la biblioteca dentro de Drupal. En
el momento de la escritura, esto significa básicamente la adición de la
"mandrill/mandrill": "1.0.*"
Dependencia para el archivo
composer.json
raíz y ejecutar composer install
. Tenga
en cuenta, sin embargo, que esto también borrará la instalación de
Drupal desde dentro de la carpeta core/
y descargará la última versión
estable en su lugar. A continuación, tendrá que editar el archivo raíz index.php
y cambiar la ruta al autoloader según estas instrucciones. Esperemos
que esta última acción no sea necesaria en el futuro, y le animo a seguir las
discusiones sobre el futuro de Composer en Drupal 8 para administrar
bibliotecas externas.
En segundo lugar, necesitamos obtener una clave API de Mandrill. Afortunadamente, esto se puede generar fácilmente desde sus páginas de administración. Una vez que lo tengamos, podemos almacenarlo dentro de un nuevo archivo creado en nuestro servidor, en cualquiera de las ubicaciones:
~/.mandrill.key /etc/mandrill.key
También
podemos pasar la clave como un parámetro de constructor a la clase
Mandrill
principal, pero de esta manera no tendremos que codificarla en
nuestro código.
En
tercer lugar, tenemos que crear un servicio para que podamos utilizar
la inyección de dependencia para pasar la clase Mandrill
en nuestro
complemento:
d8mail.services.yml:
services: d8mail.mandrill: class: Mandrill
Dependiendo de cómo haya cargado la clase Mandrill
en su aplicación, deberá cambiar el valor después de class
. Utilizando el método composer.json
, esto será suficiente.
El complemento Mail
Finalmente es el momento de crear nuestro complemento. En Drupal 8, las clases de plugin van dentro de la carpeta src/Plugin
de nuestro módulo. Dependiendo de su tipo, sin embargo, se colocan más abajo dentro de otros directorios (en nuestro caso Mail
). Vamos a escribir nuestra clase que dependerá de la biblioteca Mandrill API para enviar correos electrónicos:
src/Plugin/Mail/MandrillMail.php:
<?php namespace Drupal\d8mail\Plugin\Mail; use Drupal\Core\Mail\MailFormatHelper; use Drupal\Core\Mail\MailInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Mandrill; use Mandrill_Error; /** * Defines the Mandrill mail backend. * * @Mail( * id = "mandrill_mail", * label = @Translation("Mandrill mailer"), * description = @Translation("Sends an email using Mandrill.") * ) */ class MandrillMail implements MailInterface, ContainerFactoryPluginInterface { /** * @var Mandrill */ private $mandrill; /** * @param Mandrill $mandrill */ public function __construct(Mandrill $mandrill) { $this->mandrill = $mandrill; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $container->get('d8mail.mandrill') ); } /** * {@inheritdoc} */ public function format(array $message) { // Join the body array into one string. $message['body'] = implode("\n\n", $message['body']); // Convert any HTML to plain-text. $message['body'] = MailFormatHelper::htmlToText($message['body']); // Wrap the mail body for sending. $message['body'] = MailFormatHelper::wrapMail($message['body']); return $message; } /** * {@inheritdoc} */ public function mail(array $message) { try { $vars = [ 'html' => $message['body'], 'subject' => $message['subject'], 'from_email' => $message['from'], 'to' => array( array('email' => $message['to']) ), ]; $result = $this->mandrill->messages->send($vars); if ($result[0]['status'] !== 'sent') { return false; } return $result; } catch (Mandrill_Error $e) { return false; } } }
Hay un par de cosas a tener en cuenta antes de entrar en lo que hace la clase.
En primer lugar, las anotaciones por encima de la clase. Este es sólo el mecanismo de descubrimiento de complementos más común para Drupal 8. La
clave id
coincide con el valor que añadimos anteriormente a la matriz
de configuración system.mail.interface
, mientras que el resto son
elementos básicos de definición de complemento.
En
segundo lugar, la implementación de la interfaz
ContainerFactoryPluginInterface
mediante la cual definimos el método
create()
. Este
último es parte del proceso de inyección de dependencias mediante el
cual podemos cargar el servicio Mandrill que definimos anteriormente en
el archivo services.yml
. Esto hace que la prueba sea mucho más fácil y se considere la mejor práctica.
Como
ya he mencionado, los complementos de correo necesitan implementar la
interfaz MailInterface
que impone la existencia de los métodos format()
y mail()
. En nuestro caso, el primero hace exactamente lo mismo que el plugin PHPMail
: un poco de procesamiento del cuerpo del mensaje. Así que puede agregar su propia lógica aquí si lo desea. El
segundo método, por otra parte, es responsable de enviar el correo
hacia fuera, en nuestro caso, usando la propia API Mandrill.
Como
instruye la documentación de Mandrill, construimos un mensaje de correo
electrónico dentro de la matriz $vars
usando valores pasados del
administrador de correo a través del parámetro $message
. Estos ya se filtrarán a través de hook_mail()
, hook_mail_alter()
y el propio format()
del plugin. Todo lo que queda es enviar el correo electrónico. No
entraré en los detalles del uso de la API Mandrill, ya que puede
consultar la documentación de todas las opciones que puede utilizar.
Después
de enviar el correo electrónico y volver de Mandrill un estado sent
,
devolvemos toda la matriz de respuestas, que contiene más información. Esta matriz luego se agrega por el administrador de correo a su propia array devuelta con una clave result
. Si Mandrill tiene un problema, rechaza el correo electrónico o lanza una excepción, devuelve false
. Esto hará que el administrador de correo maneje esta situación registrando el incidente e imprimiendo un mensaje de estado.
Y eso es más o menos. Podemos borrar la caché e intentar crear otro nodo de artículo. Esta vez, el correo electrónico de notificación debe ser enviado por Mandrill en lugar del correo de PHP mail()
. Con
esto en su lugar, sin embargo, la implementación hook_mail_alter()
se
ha vuelto superflua ya que no hay encabezados que realmente estamos
enviando a Mandrill (y el texto ya es HTML). Y
para que el asunto bastante del trabajo del encargado del correo no se
utiliza, pues no estamos pasando eso a Mandrill. Pero esto sólo tiene por objeto ilustrar el proceso de cómo se puede ir sobre la creación de este. Los detalles de la implementación dependen de usted y de sus necesidades.
Conclusión
Y ahí lo tenemos. Hemos
implementado nuestro propio complemento de correo para ser utilizado
por el d8module
que iniciamos en el artículo anterior. Y debido a la naturaleza extensible de Drupal 8, ni siquiera tomar demasiado esfuerzo.
Lo que queda por hacer es perfeccionar la lógica de envío de correo y adaptarla a sus circunstancias. Esto puede significar una mayor integración entre Mandrill y tu instancia de Drupal, la construcción de buenas plantillas o lo que tienes. Además, una importante tarea restante es escribir pruebas automatizadas para esta funcionalidad. Y Drupal 8 ofrece el kit de herramientas para eso también.
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post