quarta-feira, 10 de outubro de 2012

Enviar email usando SMTP

Tive a necessidade de acrescentar em um software que estou fazendo uma classe para enviar uma mensagem via email. Precisava montar algo que conectasse ao servidor SMTP do cliente e encaminhasse a mensagem uma conta de email previamente cadastrada para este fim.
O J2SE pra variar me deu todas as ferramentas necessárias para isto. Para gerar o email utilizar o pacote JavaMail, mais especificamente o javax.mail.
Vou apresentar abaixo as classes que utilizei para conseguir enviar o mail. Eu criei:
  • um bean EmailRemetente que contem as informações do remetente incluindo os dados do servidor SMTP, porta, usuário para conexão, autenticação etc.
  • um bean EmailMensagem que contem o destinatario da mensagem e a mensagem em si
  • uma classe EnviarMensagem que trata do envio e que instancia as duas classes de remetente e destinatário
  • uma classe de teste para vocês verem como funcionam.
Vamos lá!
As classes foram criadas usando a IDE Netbeans, portanto vocês vão ver algumas coisas que o próprio Netbeans coloca, ok?

EmailRemetente foi feito na forma de um java bean, portanto o construtor não tem parâmetros e as variáveis são acessíveis via getter e setters (encapsulamento). Notem que por default coloco a porta SMTP como 25 mais tem como trocar.

/*
 *
 * Esta classe guarda os dados do rementente incluindo informações de acesso ao servidor
 * Obrigatoriamente para utilizar este bean é necessário após a criação alterar as propriedades
 * de:
 * 1) nome do Host
 * 2) email do usuario
 * 3) senha do usuario
 *
 */

package testeenvioemail;

/**
 *
 * @author Henrique
 */

public class EmailRemetente {

  private String nomeHost;
  private String porta = "25";
  private String usuarioEmail;
  private String usuarioNome;
  private String senha = "";
  private Boolean autenticar = true;

    /**
     * @return nome do Host (endereço ip ou FQDN)
     */

    public String getNomeHost() {
        return nomeHost;
    }

    /**
     * @param nomeHost nome do host SMTP que enviará a mensagem
     */

    public void setNomeHost(String nomeHost) {
        this.nomeHost = nomeHost;
    }

    /**
     * @return a porta do servidor SMTP configurada
     */

    public String getPorta() {
        return porta;
    }

    /**
     * seta a porta para um valor
     *
     * @param porta novo valor, normalmente 25, 465 ou 587
     * Google mail SSL Porta 465 StartTLS Porta 587
     * Outlook.com (ou Hotmail) StartTLS Porta 587
     * Yahoo SSL Porta 465
     *
     */

    public void setPorta(String porta) {
        this.porta = porta;
    }

    /*
     * porta default alternativa usado para new submissions (MSA)
     * muito usada quando em conjunto com StartTLS
     */

    public void setPortaAlternativa() {
        this.porta = "587";
    }
   
    /*
     * porta padrão do SMTP
     */

    public void setPortaDefault() {
        this.porta = "25";
    }
   
    /**
     * @return o email do usuario
     */

    public String getUsuarioEmail() {
        return usuarioEmail;
    }

    /**
     * @param usuario o endereço de email do usuário

     *        (utilizado para conectar ao servidor SMTP 
     *         e para preencher o campo FROM)
     */

    public void setUsuarioEmail(String usuarioEmail) {
        this.usuarioEmail = usuarioEmail;
    }

    /**
     * @return senha
     */

    public String getSenha() {
        return senha;
    }

    /**
     * @param senha pega a senha do usuário 

     *             (usado para autenticar o usuário no servidor)
     */

    public void setSenha(String senha) {
        this.senha = senha;
    }

    /**   
    * @return nome do Usuario
     */

    public String getUsuarioNome() {
        return usuarioNome;
    }

    /**
     * @param nomeUsuario texto simples com o nome do usuário
     */

    public void setUsuarioNome(String usuarioNome) {
        this.usuarioNome = usuarioNome;
    }

    /**
     * @return indica se deve fazer procedimento de autenticação
     */

    public Boolean getAutenticar() {
        return autenticar;
    }

    /**
     * @param autenticar
     */

    public void setAutenticar(Boolean autenticar) {
        this.autenticar = autenticar;

    }
}

Aqui fica a mensagem e o destinatário. O ideal seria que o destinatário fosse uma lista e que tivéssemos um método para adicionar e outro para remover destinatários da lista.

/*
 * guarda a mensagem e o remetente
 * TODO: colocar os destinatarios como uma lista
 */

package testeenvioemail;

/**
 *
 * @author Henrique
 */

public class EmailMensagem {
   
    private String emailDestinatario;
    private String nomeDestinatario;
    private String assunto;
    private String corpo;
    private String mimeCorpo = "text/plain";

    /**
     * @return email do Destinatario
     */

    public String getEmailDestinatario() {
        return emailDestinatario;
    }

    /**
     * @param emailDestinatario o email de destino
     * @param nomeDestinatario o nome por exterso do destinatario da mensagem
     */

    public void setDestinatario(String emailDestinatario, String nomeDestinario){
        this.emailDestinatario = emailDestinatario;
        this.nomeDestinatario = nomeDestinatario;
    }

    /**
     * @return the nomeDestinatario
     */

    public String getNomeDestinatario() {
        return nomeDestinatario;
    }

    /**
     * @return the assunto
     */

    public String getAssunto() {
        return assunto;
    }

    /**
     * @param assunto the assunto to set
     */

    public void setAssunto(String assunto) {
        this.assunto = assunto;
    }

    /**
     * @return the corpo
     */

    public String getCorpo() {
        return corpo;
    }

    /**
     * @param corpo the corpo to set
     */

    public void setCorpo(String corpo) {
        this.corpo = corpo;
    }

    /**
     * @return the mimeCorpo
     */

    public String getMimeCorpo() {
        return mimeCorpo;
    }

    /**
     * @param mimeCorpo the mimeCorpo to set
     */

    public void setMimeCorpo(String mimeCorpo) {
        this.mimeCorpo = mimeCorpo;
    }
   
}


E agora a classe que efetivamente envia o email:
/*
 * Para executar este código é preciso colocar o JavaMail (mail.jar) no classpath
 * a biblioteca pode ser obtida no site da oracle
 * no endereço http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-eeplat-419426.html#javamail-1.4.5-oth-JPR
 *
 */

package testeenvioemail;

import java.io.UnsupportedEncodingException;
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
/**
 *
 * @author Henrique
 */

public class EnviarEmail {
   
    /*
     * variavel interna utilizada para gravar a mensagem
     */

    private MimeMessage mimeMsg;
   
    public EnviarEmail(final EmailRemetente rmt, EmailMensagem msg) throws MessagingException, UnsupportedEncodingException {

        Properties props = System.getProperties();
        props.put("mail.transport.protocol", "smtp");
        props.put("mail.smtp.host", rmt.getNomeHost());
        props.put("mail.smtp.port", rmt.getPorta());
        props.put("mail.smtp.user", rmt.getUsuarioEmail());
        if (rmt.getAutenticar()) {
            props.put("mail.smtp.auth", "true");
        } else {
            props.put("mail.smtp.auth", "false");
        }
        //
        Authenticator auth = new Authenticator() {
            @Override
            public PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(rmt.getUsuarioEmail(),

                                                  rmt.getSenha());
            }           
        };

        // obtem a sessão
        Session session = Session.getDefaultInstance(props, auth);
        mimeMsg = new MimeMessage(session);
        mimeMsg.setFrom(new InternetAddress(rmt.getUsuarioEmail(),

                                            rmt.getUsuarioNome()));
        mimeMsg.addRecipient(RecipientType.TO,

                             new InternetAddress(msg.getEmailDestinatario(),
                                                 msg.getNomeDestinatario()));
        mimeMsg.setSubject(msg.getAssunto());
        mimeMsg.setContent(msg.getCorpo(), msg.getMimeCorpo());

        Transport.send(mimeMsg); // enviar a mensagem       
    }
   
}


Alguns pontos importantes:
  • veja que o parâmetro rmt está como final. Isto acontece porque utilizamos dentro da definição da classe Autheticator.
  • Authenticator é uma classe abstrata e temos que implementar getPasswordAuthentication.
  • Em properties definimos o protocolo de comunicação "mail.transport.protocol" : isto não é obrigatório. Nos meus testes, vi que não fazia diferença nos resultados. Note que o protocolo está explícito nas demais entradas de props. Por exemplo "mail.smtp.host"
  • Session representa a sessão de email, armazenando propriedades e padrões usados pela API de email. Uma única default session pode ser compartilhada entre diversas aplicações no desktop, mas se você quiser pode criar uma sessão exclusiva. Eu optei por usar a sessão default.
  • Transport modela na API o transporte da mensagem. Utilizamos o método send para enviar a mensagem MIME que criamos antes.
  • MimeMessage é uma subclasse de Message. Para implementação poderíamos utilizar SMTPMessage que é uma classe de MimeMessage, mas no momento não precisamos das características adicionais apresentadas por SMTPMessage. Precisamos criar na mensagem as informações de:
    • From: de quem vem a mensagem (rmt)
    • To: para quem vai a mensagem (msg).
    • Subject: o assunto
    • Content: o texto que queremos enviar
  • Existe um método addRecipients que permite criar várias destinatários de uma só vez. addRecipient pode também ser chamado várias vezes para acrescentar os destinatários um a um.
  • ao invés de setContent poderíamos utilizar setText se o MIME type for "text".



No próximo post mostro para vocês o teste destas classes.

Nenhum comentário:

Postar um comentário