Estudios De Caso

Cómo triplicó Launch School Academy la interacción de los estudiantes

Este artículo está escrito por Kevin Wang, instructor jefe en Tealeaf Academy (Launch School). Tealeaf Academy es una escuela online para desarrolladores y ofrece bootcamps online intensivos basados en proyectos sobre desarrollo web. ¡Si te parece útil este artículo, deberías echarles un vistazo!

En Tealeaf Academy, crear una experiencia de “estudiar juntos, progresar juntos” para nuestros estudiantes es fundamental en nuestra forma de enseñar. Una de nuestras herramientas principales es el foro de debate, donde los estudiantes hacen preguntas, comparten ideas, colaboran en los deberes y los profesores intervienen rápidamente para ayudar a los estudiantes a resolver sus problemas. Una de nuestras prioridades recientes era reducir la fricción en el uso del foro de debate y fomentar más debates con una notificación por email complementaria y un flujo de trabajo de “responder al email para publicar en el foro de debate”.

Una vez que implementamos el siguiente código utilizando la API de rutas de Mailgun, la actividad en nuestro foro de debate se triplicó, y ahora las preguntas suelen responderse en una hora, a veces incluso en minutos, y los estudiantes pueden pasar al siguiente conjunto de tareas mucho más rápido. Así es como lo hicimos:

Nuestro flujo de trabajo sería el siguiente:

  1. Cuando se crea una publicación (muy probablemente, una pregunta), todos los participantes del curso reciben una notificación por email
  2. Los participantes del curso pueden responder a las notificaciones por email directamente desde su bandeja de entrada de email, sin tener que iniciar sesión en el curso
  3. Esa respuesta se publicará en el foro de debate online, y también se envía a otros participantes del curso para mantener la conversación en marcha.

Por qué elegimos Mailgun

La pieza clave de este flujo de trabajo es recibir y analizar mensajes de email entrantes. Buscamos entre varios proveedores de servicios de envío de emails, y al final elegimos Mailgun porque:

  1. Es muy fácil de usar para los desarrolladores: somos desarrolladores y Mailgun habla nuestro idioma. Las API exponen muchas opciones de bajo nivel que permiten hacer ajustes. Nos gustan las rutas en particular: es una buena capa de abstracción que hace que la integración con las aplicaciones sea muy fácil. (mira cómo lo usamos a continuación)
  2. Es el servicio más completo en características que hemos encontrado: podemos usar Mailgun para emails transaccionales, campañas y también para listas de contactos. Es estupendo tener un solo proveedor de servicios para encargarse de todo lo que necesitamos.
  3. El precio es razonable y el proceso para pasar a un plan superior con IP dedicada y DKIM personalizado está muy bien, aunque todavía no lo necesitemos.
  4. La asistencia es de primera categoría. Hay un chat en directo donde puedo hablar con sus desarrolladores directamente sobre los problemas y nos ha resultado muy útil para resolverlos.

Configuración de la infraestructura de email

  • El primer paso fue crear un nuevo dominio en Mailgun. En nuestro caso, es messaging.gotealeaf.com, el cual utilizamos para enviar y recibir emails.
  • A continuación, creamos un MailgunGateway como nuestro wrapper para la API de Mailgun. Este wrapper se encarga de todas nuestras interacciones con Mailgun a través de nuestra cuenta. Aquí utilizamos la API send_batch_messages de Mailgun para enviar emails en HTML. Nos permite enviar un mensaje a múltiples destinatarios con una sola llamada a la API. Mantenemos nuestra clave de API como variables de entorno en el servidor para mayor seguridad. También hay un simple filtro de entrega de modo que no se envían emails en el entorno de desarrollo; en staging, todos los emails se envían a Chris (mi cofundador) y a mí, para que podamos probar las cosas sin temor a enviar spam a nuestros usuarios; solo en el entorno de producción se envían emails a usuarios reales.
                            

                                class MailgunGateway  
  def send_batch_message(options={})
    RestClient.post(messaging_api_end_point,
        from: default_sender,
        to: delivery_filter(options[:to]),
        subject: options[:subject],
        html: options[:body],
        :"h:Reply-To" => options[:reply_to],
        :"recipient-variables" => options[:recipient_variables]
        ) if Rails.env.staging? || Rails.env.production?
    end
  end

  private

  def default_sender
    "Tealeaf Academy "
  end

  def api_key
    @api_key ||= ENV['mailgun_api_key']
  end

  def messaging_api_end_point
    @messaging_api_end_piont ||= 
        "https://api:#{api_key}@api.mailgun.net/v2/messaging.gotealeaf.com/messages"
  end

  def delivery_filter(emails)
    Rails.env.production? ? emails : "kevin@gotealeaf.com, chris@gotealeaf.com"
  end
end
                            
                        

Envía notificaciones por email para nuevas publicaciones o comentarios

Una vez que se crea una publicación o comentario, enviamos una notificación por email a todos los participantes del curso. Por ahora estamos enviando emails de forma sincrónica, pero a medida que tengamos más usuarios, probablemente querremos delegar esto a un trabajo en segundo plano.

                            

                                Launch School Code 1class Courses::PostsController < AuthenticatedController  
  expose(:course)
  expose(:posts) { course.posts }
  expose(:post)

  def create
    post.user = current_user
    post.save
    CourseNotifier.new(course).notify_course_participants_on_new_discussion(post)
    redirect_to course_home_path(course)
  end

  ...
end

class Courses::Posts::CommentsController < AuthenticatedController  
  expose(:course)
  expose(:posts) { course.posts }
  expose(:post)
  expose(:comments) { post.comments }
  expose(:comment)

  def create
    comment.user = current_user
    comment.save
    CourseNotifier.new(course).notify_course_participants_on_new_discussion(comment)
    redirect_to course_home_path(course)
  end

  ...
end
                            
                        

CourseNotifier es la clase donde ponemos la lógica específica de nuestra aplicación sobre las notificaciones. Ten en cuenta que MailgunGateway se inyecta como el gateway predeterminado: esto es de cuando solíamos tener varios proveedores de servicios de envío de emails para campañas, listas y emails transaccionales. ¡Ahora es menos necesario, ya que consolidamos todas las necesidades de entrega de emails en Mailgun!

                            

                                class CourseNotifier

  attr_reader :course, :gateway

  def initialize(course, gateway=MailgunGateway.new)
    @course = course
    @gateway = gateway
  end

  def notify_course_participants_on_new_discussion(discussion)
    gateway.send_batch_message(
      to: notification_recipients(discussion).map(&:email).join(", "),
      subject: notification_subject(discussion),
      body: discussion_notification_text(discussion),
      reply_to: reply_to_address(discussion),
      recipient_variables: recipient_variables(
        notification_recipients(discussion)
      )
    )
  end

  ...

  private

  def notification_recipients(discussion)
    course.participants.reject {|participant| participant.email == discussion.user.email }
  end

  def notification_subject(discussion)
    discussion.is_a?(Post) ?
    "[Tealeaf Academy] #{discussion.user.name} Posted a New Message on the Discussion Board" :
    "[Tealeaf Academy] #{discussion.user.name} Replied to a Message on the Discussion Board"
  end

  def reply_to_address(discussion)
    "reply+#{discussion.token}@messaging.gotealeaf.com"
  end

  def recipient_variables(recipients)
    vars = recipients.map do |recipient|
      ""#{recipient.email}": {"name":"#{recipient.name}"}"
    end
    "{#{vars.join(', ')}}"
  end

  def discussion_notification_text(discussion)
<<-EMAIL


Hi %recipient.name%,

<p>#{discussion.user.name} says on the course dicussion board:</p>

"#{discussion.text}"
<br />
<p>Reply to this email directly or <a href="http://www.gotealeaf.com/courses/#{course.slug}/home">view it on the discussion board</a></p>

EMAIL  
  end
end
                            
                        

El replytoaddress es donde insertamos el token de la publicación en el encabezado «Reply-To». El contenido de los emails es bastante simple, así que simplemente lo ponemos aquí en la clase. Si tuviéramos un estilo de email más elaborado, habríamos utilizado la renderización de plantillas para manejarlo. Con la API sendbatchmessage de Mailgun, podemos llamar a la API solo una vez para enviar a múltiples destinatarios, y el método recipient_variables es donde personalizamos los mensajes de email para cada destinatario e incluimos sus nombres para darle un toque personal.

Gestión de mensajes entrantes en la aplicación

En Mailgun, bajo «Routes» en el Panel de Control, creamos una ruta como la siguiente:

  • Expresión de filtro: match_recipient(«reply+(.*)@messaging.gotealeaf.com»)
  • Acción: forward(«http://www.gotealeaf.com/api/incoming_messages/?post_token=1»)

Cuando un usuario responde a un email, lo responde a una dirección de email como «reply+fj42gq4v@messaging.gotealeaf.com», y esta ruta reenviará el email a un webhook que exponemos para manejar los mensajes entrantes.

                            

                                class Api::IncomingMessagesController < ApplicationController  
  skip_before_filter :verify_authenticity_token

  def create
    user = User.where(email: params['sender']).first
    post = Post.where(token: params['post_token']).first
    text = params["stripped-text"]
    if post && user && text.present?
      comment = post.comments.create(user: user, text: text)
      CourseNotifier.new(post.course).notify_course_participants_on_new_discussion(comment)
    end
    head(200)
  end
end
                            
                        

Aquí, usamos el email del remitente para encontrar al autor, y usamos el token de la publicación para encontrar la publicación bajo la cual se debe cotejar esta respuesta. ¡Mailgun nos da el útil texto sin formato que elimina la parte del mensaje original para que solo contenga la respuesta en sí! Al final, devolvemos un encabezado 200 para decirle a Mailgun que esta interacción fue exitosa; de lo contrario, Mailgun pensará que nuestro servidor está caído y seguirá intentando llamar fielmente a nuestro webhook.

El resultado de implementar este flujo de trabajo es impresionante: la actividad en nuestro foro de discusión se triplicó, y las preguntas ahora suelen responderse en menos de una hora, a veces incluso en minutos, los estudiantes pueden pasar a la siguiente serie de tareas mucho más rápido y estamos muy contentos de cómo resultó.

«Podemos garantizar un mejor servicio para nuestros profesionales del marketing al usar Mailgun. Ellos cuentan con nosotros y nosotros contamos con Mailgun: y esta relación nos ayuda a mantener la credibilidad ante nuestros clientes».
Photo of Paulius Milisauskas
Paulius Milisauskas Vicepresidente de Operaciones de Cliente
¡Mantenme informado/a! Recibe excelentes recursos en tu bandeja de entrada cada semana.
Envíame la newsletter de Mailjet. Acepto expresamente recibir la newsletter y sé que puedo darme de baja fácilmente en cualquier momento.

¡Consulta mensualmente tu bandeja de entrada para recibir la newsletter de Mailjet!