Enviando Emails via STMP (Gmail) com Action Mailer do Rails - Formulário de Contato e Model sem Tabela

Fala galera, beleza? Hoje venho mostrar como enviar emails via SMTP (Gmail) com Ruby on Rails (3.2.8) através do Action Mailer e para isso estarei criando um formulário de contato com model (para desfrutarmos das validações e outros recursos) sem tabela (tableless model) como exemplo.

Gerando o Formulário com Scaffold

Formulários de contato são constituídos por campos que quando preenchidos são enviados para uma url e executam algo certo?

Então para agilizar irei gerar um scaffold com os dados que preciso e depois removerei os códigos desnecessários.

rails g scaffold Contact name:string email:string subject:string message:text

Model sem Tabela (tableless model)

Olhe para o model Contact que acabamos de criar e ele deve estar como abaixo:

class Contact < ActiveRecord::Base
  attr_accessible :email, :message, :name, :subject
end

Observe que ele herda da classe ActiveRecord, mas como não iremos usar tabela, vamos fazer algumas mudanças..

  1. Primeiro vamos retirar a herança do ActiveRecord pois não usaremos nenhum recurso de banco de dados
  2. Vamos incluir e extender algumas classes necessárias
  3. Criar dois métodos necessários para a utilização do model sem tabela
  4. Definir métodos acessores

Feito as mudanças, nosso model deve se parecer com esse:

class Contact
  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend ActiveModel::Naming

  attr_accessor :name, :subject, :message, :email

  def initialize(attributes = {})
    attributes.each do |name, value|
      send("#{name}=", value)
    end
  end

  def persisted?
    false
  end
end

Removendo o Desnecessário

Como não iremos precisar das funcionalidades de atualização (edição), visualização, listagem e exclusão vamos remover elas. Exclua as views index, edit e show da pasta views/contacts, remova as respectivas actions do contacts_controller.rb e mais algumas coisas que não serão necessárias. Nosso controller fica assim por enquanto:

class ContactsController < ApplicationController
  def new
    @contact = Contact.new
  end

  def create
    @contact = Contact.new(params[:contact])

    if @contact.valid?
      redirect_to :action => 'new'
      return  
    end

    render :action => 'new'
  end
end

Repare que uma das alterações que fizemos foi trocar o .save para .valid? da action create, isso serve para validar com o model antes de enviarmos o email com dados do contato.

Criando um Mailer

Vamos criar um mailer que será reponsável por determinar o template e alterar algumas opções. Execute o comando abaixo no terminal na pasta do projeto:

rails generate mailer ContactMailer

Dentro da pasta app/mailers foi criado um arquivo chamado contact_mailer.rb, usaremos ele para definir algumas opções do envio.

Vamos criar um método chamado contact_message que enviará as mensagens de contato:

class ContactMailer < ActionMailer::Base
  default :from => 'email_remetente@gmail.com'

  def contact_message(contact)
    @contact = contact
    mail(:to => 'destinatario@provedor.com', :subject => 'Mensagem de Contato')
  end
end

Aqui definimos o remetente, destinatário e assunto da mensagem além de passarmos os dados de contato para a view.

Criando as Views do Mailer

Crie um arquivo chamado contact_message.html.erb e outro contact_message.text.erb em app/views/contact_mailer/ para termos as views HTML e texto respectivamente para nosso mailer, esses arquivos conterão a mensagem propriamente. Minha view HTML ficou assim:

<h1>Mensagem de contato</h1>
<h2>Data de envio: <%= Time.now.strftime("%d/%m/%Y %H:%M") %></h2>

<p><strong>Visitante: </strong><%= @contact['name'] %></p>

<p><strong>Email: </strong><%= @contact['email'] %></p>

<% if @contact['subject'].present? %>
  <p><strong>Assunto: </strong><%= @contact['subject'] %></p>
<% end %>

<p><strong>Mensagem:</strong></p>
<p><%= @contact['message'] %></p>
Assim como em views normais você pode usar variáveis de instâncias que estiverem definidas no método da classe mailer.

Definindo Configurações SMTP

Para enviarmos as mensagens via SMTP, precisamos informar os dados que serão utilizados, para isso abra o arquivo de configuração da aplicação (application.rb) e defina as configurações do Gmail como abaixo (preenchendo com os dados do remetente):

config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  :address              => "smtp.gmail.com",
  :port                 => 587,
  :domain               => 'gmail.com',
  :user_name            => 'usuario_remetente',
  :password             => 'senha123',
  :authentication       => 'plain',
  :enable_starttls_auto => true 
}
# Para debug apenas, é melhor que a linha abaixo seja adicionado apenas no ambiente de desenvolvimento
config.action_mailer.raise_delivery_errors = true
Se você quiser pode adicionar uma configuração de SMTP para cada ambiente, basta adicionar nos arquivos respectivos dentro da pasta config/environmentes, no caso acima defino uma para todos.

Enviando Emails

Agora só precisamos adicionar a chamada do método responsável por enviar emails (linha 10) em nosso controller, veja como fica:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ContactsController < ApplicationController
  def new
    @contact = Contact.new
  end

  def create
    @contact = Contact.new(params[:contact])

    if @contact.valid?
      ContactMailer.contact_message(params[:contact]).deliver
      flash[:notice] = 'Mensagem enviado com sucesso'
      redirect_to :action => 'new'
      return  
    end

    render :action => 'mew'
  end
end

O envio já está funcionando, faça um teste!

Adicionando Validações

Vamos adicionar algumas validações no formulário, para isso abro o model Contact e adiciono algumas linhas, ficando como abaixo:

class Contact 
  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend ActiveModel::Naming

  attr_accessor :name, :subject, :message, :email

  validates :name,
            :length => {:in => 2..50}

  validates :email,
            :format => { :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i }  

  validates :message,
            :length => {:in => 10..750}

  def initialize(attributes = {})
    attributes.each do |name, value|
      send("#{name}=", value)
    end
  end

  def persisted?
    false
  end
end

Agora se alguém tentar submeter o formulário vazio não conseguirá..

Pronto, temos nosso formulário de contato com validação e envio de emails por SMTP funcionando.

Por hoje é só pessoal, o que vocês acharam?

Até mais.

Written on November 6, 2012

Share: