Estudos de caso

Como a Launch School Academy aumentou o engajamento dos alunos em 3x

Esta postagem foi escrita por Kevin Wang, Instrutor Chefe da Tealeaf Academy (Launch School). A Tealeaf Academy é uma escola online para desenvolvedores e oferece bootcamps online intensivos e baseados em projetos sobre desenvolvimento web. Se você acha este post útil, deveria conferi-los!

Na Tealeaf Academy, criar uma experiência de “Estudar Juntos, Progredir Juntos” para os nossos alunos está no centro da nossa forma de ensinar. Uma das nossas principais ferramentas é o fórum de discussão, onde os alunos fazem perguntas, compartilham ideias, colaboram nas tarefas de casa e os professores entram rapidamente para ajudar os alunos a resolverem seus problemas. Uma de nossas prioridades recentes era reduzir o atrito no uso do fórum de discussão e encorajar mais discussões com uma notificação por e-mail complementar e um fluxo de trabalho de “responder ao e-mail para postar no fórum de discussão”.

Assim que implementamos o código abaixo usando a API Routes do Mailgun, a atividade no nosso fórum de discussão aumentou três vezes, e as perguntas agora normalmente são respondidas em uma hora, às vezes até em minutos, e os alunos conseguem passar para o próximo conjunto de tarefas muito mais rapidamente. Veja como fizemos isso:

Nosso fluxo de trabalho funcionaria da seguinte maneira:

  1. Quando uma postagem (muito provavelmente, uma pergunta) é criada, todos os participantes do curso são avisados por uma notificação por e-mail
  2. Os participantes do curso podem responder às notificações por e-mail diretamente da sua caixa de entrada de e-mail, sem precisarem entrar no curso
  3. Essa resposta será publicada no fórum de discussão online e também é enviada para outros participantes do curso, para manter a conversa fluindo.

Por que escolhemos o Mailgun

A peça-chave deste fluxo de trabalho é receber e analisar as mensagens de e-mail de entrada. Nós pesquisamos por vários provedores de serviços de e-mail, e no final escolhemos o Mailgun porque:

  1. Ele é muito amigável para desenvolvedores – Nós somos desenvolvedores, e o Mailgun fala a nossa língua. As APIs expõem diversas opções de baixo nível que permitem ajustes. Nós gostamos das rotas em particular – É uma ótima camada de abstração que torna a integração com os aplicativos muito fácil. (veja como nós o usamos abaixo)
  2. É o serviço mais completo em recursos que encontramos – podemos usar o Mailgun para e-mails transacionais, campanhas, bem como listas de e-mails – é bom ter apenas um provedor de serviços para lidar com tudo o que precisamos.
  3. O preço é razoável e o caminho para fazer upgrade para IP dedicado e DKIM personalizado é ótimo, mesmo que ainda não precisemos disso.
  4. O suporte é de primeira linha. Há um chat ao vivo onde eu posso conversar com os desenvolvedores deles diretamente sobre os problemas, e tem sido muito útil para nós resolvermos os problemas.

Configurando a infraestrutura de e-mail

  • O primeiro passo foi criar um novo domínio no Mailgun. No nosso caso, é messaging.gotealeaf.com, o qual usamos para enviar e receber e-mails.
  • Em seguida, criamos um MailgunGateway como nosso wrapper para a API do Mailgun. Esse wrapper cuida de todas as nossas interações com o Mailgun através da nossa conta. Aqui usamos a API send_batch_messages do Mailgun para enviar e-mails em HTML. Ela nos permite enviar uma mensagem para vários destinatários com uma única chamada de API. Mantemos a nossa chave de API como variáveis de ambiente no servidor para maior segurança. Há também um filtro de entrega simples para que nenhum e-mail seja enviado no ambiente de desenvolvimento; No ambiente de homologação, todos os e-mails são enviados para Chris (meu cofundador) e para mim, para que possamos testar as coisas sem o receio de enviar spam aos nossos usuários; Somente no ambiente de produção os e-mails são enviados para usuários reais.
                            

                                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
                            
                        

Enviar notificações por e-mail para nova postagem ou comentário

Assim que uma postagem ou comentário é criado, enviamos uma notificação por e-mail para todos os participantes do curso. Estamos enviando e-mails de forma síncrona por enquanto, mas, à medida que tivermos mais usuários, provavelmente vamos querer transferir isso para um trabalho em 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
                            
                        

O CourseNotifier é a classe onde colocamos a lógica específica do nosso aplicativo para notificações. Observe que o MailgunGateway é injetado como o gateway padrão – isso é da época em que costumávamos ter vários provedores de serviços de e-mail para campanhas, listas e e-mails transacionais. Isso é menos necessário agora que consolidamos todas as necessidades de entrega de e-mail no 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
                            
                        

O replytoaddress é onde inserimos o token da postagem no cabeçalho “Reply-To”. O conteúdo dos e-mails é bem simples, então nós apenas o colocamos aqui na classe. Se tivéssemos um estilo de e-mail mais elaborado, teríamos usado a renderização de modelo para lidar com isso. Com a API sendbatchmessage do Mailgun, podemos chamar a API apenas uma vez para enviar a vários destinatários, e o método recipient_variables é onde personalizamos as mensagens de e-mail para cada destinatário para incluir os seus nomes e adicionar um toque pessoal.

Lidando com mensagens de entrada no aplicativo

Indo para o Mailgun, em “Routes” no Painel de Controle, criamos uma rota da seguinte forma:

  • Expressão de Filtro: match_recipient(“reply+(.*)@messaging.gotealeaf.com”)
  • Ação: forward(“http://www.gotealeaf.com/api/incoming_messages/?post_token=1”)

Quando um usuário responde a um e-mail, ele o responde para um endereço de e-mail como “reply+fj42gq4v@messaging.gotealeaf.com”, e essa rota encaminhará o e-mail para um webhook que expomos para lidar com mensagens de entrada.

                            

                                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
                            
                        

Aqui, usamos o e-mail do remetente para encontrar o autor, e usamos o token da postagem para encontrar a postagem sob a qual essa resposta deve ser agrupada. O Mailgun nos fornece o texto limpo, que é muito útil e remove a parte original da mensagem para conter apenas a resposta real! No final, retornamos um cabeçalho 200 para informar ao Mailgun que essa interação foi bem-sucedida, caso contrário, o Mailgun achará que nosso servidor está fora do ar e continuará fielmente tentando chamar o nosso webhook.

O resultado da implementação desse fluxo de trabalho é impressionante – a atividade no nosso fórum de discussão aumentou três vezes, e as perguntas agora normalmente são respondidas em uma hora, às vezes até em minutos, os alunos conseguem passar para o próximo conjunto de tarefas muito mais rapidamente e estamos muito felizes com o resultado.

“Conseguimos garantir melhor atendimento aos nossos profissionais de marketing usando o Mailgun. Eles contam conosco, e nós contamos com o Mailgun: e esse relacionamento nos ajuda a manter a credibilidade com nossos clientes.”
Photo of Paulius Milisauskas
Paulius Milisauskas Vice-presidente de Operações de Clientes
Mantenha-me informado! Receba ótimos recursos em sua caixa de entrada toda semana.
Envie-me a newsletter da Mailjet. Eu concordo expressamente em receber a newsletter e sei que posso cancelar a inscrição facilmente a qualquer momento.

Verifique sua caixa de entrada mensalmente para receber sua newsletter da Mailjet!