terça-feira, 23 de outubro de 2012

Serialização Parte II


Continuando o post anterior.... Vamos ver agora dois aspectos diferentes da serialização. Primeiro vamos generalizar a classe que tinhamos feito no post anterior.

Vamos ver a classe de serialização:

Vamos alterar agora a nossa chamada para o exemplo. Notem que a única diferença real é que agora temos que fazer o cast da linha 35 abaixo:


Rodamos a aplicação. Ok... Ela continua rodando!


Agora vamos ver outra opção. E se nós não quisermos que uma propriedade pública seja gravada (sei lá por que!). Para isto vamos derivar (o termo correto seria extender) uma classe nova a partir da ClasseSerializada que utilizamos no exemplo anterior. Vamos acrescentar um novo inteiro que chamaremos, com bastante inventividade, de inteiro2 e vamos fazer com que inteiro não seja serializado.

Vou dividir a apresentação da classe em duas partes só para ficar mais fácil a explicação.


Primeiro vamos notar como foi criada a classe
public class ClasseSerializada2 extends ClasseSerializada
quer dizer que estamos herdando na ClasseSerializada2 tudo que já foi feito na classe mãe. Usamos extends para dizer ao Java que estamos fazendo a classe filha.

Nas linhas 20 a 26 estamos criando a nova propriedade e encapsulando-a.

Vocês se lembram que tínhamos um método print para poder dar saída na console dos valores das propriedades? Como acrescentamos uma nova temos que fazer uma alteração para incluir a nova propriedade na impressão. Poderíamos criar um novo método imprimindo todas as propriedades, mas vamos aproveitar a facilidade que a herança nos permite.

Temos que fazer duas coisas para o código funcionar:
  • veja na linha 31 que colocamos uma anotação de Override, que indica ao java que este método substitui o da classe mãe
  • na linha 33 damos saída na nova propriedade
  • na linha 34 utilizamos um super.print(). Este super indica a classe mãe, assim estamos chamando dentro deste método da classe filha, o método original da classe mãe.
Vamos agora a segunda parte da classe. O procedimento de serialização verifica as propriedades que tenham uma propriedade transiente verdadeira, assim para que ela seja escondida basta trocar este valor para falso.

Como fazemos isto? Utilizamos uma classe java.beans.Introspector. Esta classe permite verificar as propriedades, eventos e métodos suportados por um bean. No nosso caso procuramos pela PropertyDescriptor cujo nome seja igual ao da propriedade que queremos ocultar (vejam as linhas 46 a 50).
Tendo localizado basta fazer o valor ser falso.

Você vai falar que não é isto que estou fazendo. É verdade!
No meu exemplo, eu na verdade estou trocando o status da propriedade. Se está true vira false e vice versa.

Como eu já sei que esta propriedade é criada por default como TRUE, ao chamar togglePropriedade("inteiro") o efeito que consigo é desativar transient da propriedade inteiro.

Dava para usar um operador ternário substituindo as linhas 51 a 55.

Vamos a teste. A classe é a mesma do exemplo passado ... TesteSerializacao. Somente foi adaptada para chamar a ClasseSerializada2.


Veja que interessante. A saída dos inteiros é invertida, primeiro aparece inteiro2 e depois inteiro. Está claro o porque?


Depois que a classe de deserializada o inteiro volta como zero. Quer dizer que ele não foi lido ou gravado? Vamos ver a saída XML para entender:
Onde foi parar <void property="inteiro"> ? Não existe no arquivo XML ... quer dizer que nossa alteração funcionou. Esta propriedade não foi serializada.

;-) Gostaram do visual do Notepad++?

domingo, 21 de outubro de 2012

Já ouviu falar em serialização ?

De forma genérica a serialização é uma técnica usada para persistir objetos em um programa, em outras palavras, consiste em:
  • gravar os dados dos objetos em um banco de dados e/ou arquivos,
  • fazer a transmissão remota de objetos via rede.
Serializar é colocar os valores que o objeto está utilizando (suas propriedades) de uma forma que fique em série (sequencial). Fazendo isto estamos tornando o objeto Serializable, e, tornando um objeto Serializable, estamos atribuindo essa qualidade a ele, e dando privilégios para que o mesmo possa ser gravado em disco ou enviado por rede.

Na serialização podem ser gravados os atributos públicos e privados para um stream. O processo inverso é chamado - deserialização, que consiste em restaurar os atributos de um objeto gravado em um stream.

Vamos considerar a seguinte classe:
/*
* Esta classe será utilizada para exemplo de serialização XML
* Notem que ela tem o formato de um bean
*
* Temos algumas propriedades: inteiro, string, boolean, array
*
*/
package serializacao;
/**
*
* @author Henrique
*/
public class ClasseSerializada1 {
  /*
   * Propriedade inteiro
   */
  int i;
  public int getInteiro() { return i; }
  public void setInteiro(int i) { this.i = i; }

  /*
   * Propriedade minhaString
   */
  String s;
  public String getMinhaString() { return s; }
  public void setMinhaString(String s) { this.s = s;}

  /*
   * Propriedade Array de inteiro
   */
  int[] ia = new int[0];
  public int[] getArrayInteiro() { return ia; }
  public void setArrayInteiro(int[] iarray) {this.ia = iarray; }

  /*
   * Imprime as propriedades (usado no teste para vermos o que está no objeto)
   */
  public void print() {
    System.out.println(getInteiro());
     System.out.println(getMinhaString());
     int[] a = getArrayInteiro();
     System.out.print("[");
     for(int j = 0; j < a.length; j++) {
       System.out.print(a[j]+" ");
     }
     System.out.println("]");
  }
}

Notem que existem 3 propriedades públicas (encapsuladas com getters e setters).
Vamos criar uma outra classe para fazer a gravação e leitura. Notem que o processo é bastante parecido com a leitura e gravação de arquivos e por isto utilizamos Buffered___Stream e File___Stream.

O procedimento é bastante simples




  • Fazemos (na escrita) o encadeamento de XMLEncoder(BufferedOutputStream(FileOutputStream))
  • Usamos o XMLEncoder.writeObject para escrever o objeto no arquivo
Pronto!!!
Para ler é só fazer o inverso:

  • chamar XMLDecoder(BufferedInputStream(FileInputStream))
  • Usar XMLDecoder.readObject
    • Prestar atenção que temos que fazer um cast da classe correta

/*
* classe para teste de funcionamento
*/
package serializacao;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/**
*
* @author Henrique
*/
public class Serializacao1 {
  /*
   * A classe XMLEncoder serializa um objeto parecido com java.io.ObjectOutput
   *  --> é por isto que transferimos as streams para gerar o arquivo de
   * O XMLEncoder somente persiste as propriedades públicas das classes
   * Para cada propriedade pública, XMLEncoder chama o método getter
   * (getPropriedade) correspondente e persiste o valor retornado
   *
   * Desta forma qualquer propriedade privada (que não possuir getter e setter)
   * não será persistida ==> veremos isto em outro post
  */
  public void serializar(String nomeArquivo, ClasseSerializada1 obj) {
   try {
      // Serializa o object no arquivo XML
      XMLEncoder encoder;
      encoder = new XMLEncoder(
      new BufferedOutputStream(
        new FileOutputStream(nomeArquivo)));
      encoder.writeObject(obj);
      encoder.close();
   } catch (FileNotFoundException e) {
     // imprime erro na console
     System.out.println(e.getMessage());
   }
  }

  /*
   * Na deserialização, um objeto criado é inicializado com os valores
   * persistidos no arquivo XML (as propriedades públicas)
   *
   * le o arquivo serializado para dentro do objeto ClasseSerializada
   * retorno o objeto lido do arquivo XML
   */
  public ClasseSerializada1 deserializar(String nomeArquivo) {
    ClasseSerializada1 obj = null;
    try {
      XMLDecoder decoder = new XMLDecoder(
      new BufferedInputStream(
         new FileInputStream(nomeArquivo)));
      obj = (ClasseSerializada1) decoder.readObject();
      decoder.close();
    } catch (FileNotFoundException e) {
      // imprime erro na console
      System.out.println(e.getMessage());
    }
    return obj; // retorna o objeto lido do arquivo XML
  }

}
 



Agora uma classe simples de teste.
/*
* classe para teste de funcionamento

  */ 
 package serializacao;
  /**
      * 

    * @author Henrique
    */
 public class TesteSerializacao { 

  /**   * @param args the command line arguments
   */ 
  public static void main(String[] args) { 

    static String nomeArquivoXML = "classeserializada.xml";
 

    Serializacao1 s1 = new Serializacao1();
    ClasseSerializada o = new ClasseSerializada();
    // define as propriedades
    o.setInteiro(1);
    o.setMinhaString("Esta string será serializada");
    o.setArrayInteiro(new int[]{1, 2, 3, 4});
    // imprime para conferirmos os resultados
    System.out.println("*************** Objeto criado");
    o.print();
    // grava (serializa) o objeto o
    s1.serializar(nomeArquivoXML, o);
    // faz alterações nos campos para podermos ver que
    // a deserialização funciona
    o.setInteiro(3);
    o.setMinhaString("string alterada");
    o.setArrayInteiro(new int[]{1, 2});
    System.out.println("*************** Objeto alterado");
    o.print(); // imprime o objeto alterado para vermos
    // busca os dados a partir do arquivo XML
    o = deserializar(nomeArquivoXML);
    System.out.println("********** Objeto deserializado");
    o.print(); // gera a mesma saída do primeiro o.print() deste método
  }
}


O arquivo XML gerado está mostrado abaixo. Notem que a classe serializada está identificada (pacote + classe) e as propriedades estão todas listadas e identificadas.

<?xml version="1.0" encoding="UTF-8"?>
<java class="java.beans.XMLDecoder" version="1.7.0_07">
<object class="serializacao.ClasseSerializada">
<void property="arrayInteiro">
  <array class="int" length="4">
    <void index="0"> <int>1</int> </void>
    <void index="1"> <int>2</int> </void>
    <void index="2"> <int>3</int> </void>
    <void index="3"> <int>4</int> </void>
  </array>
</void>
<void property="inteiro">
  <int>1</int>
</void>
<void property="minhaString">
  <string>Esta string será serializada</string>
</void>
</object>
</java>

Vemos no próximo posto como impedir uma propriedade pública de ser serializada e como serializar uma propriedade privada.

Podemos tornar a classe Serializacao1 mais genérica, recebendo e devolvendo objetos da classe  Object e fazendo o cast fora.


public class Serializacao {
  public void serializar(String nomeArquivo, Object obj) {
      ... // fica tudo igual

   }

  public Object deserializar(String nomeArquivo) {
    Object obj = null;
    try {
      XMLDecoder decoder = new XMLDecoder(
      new BufferedInputStream(
         new FileInputStream(nomeArquivo)));
      obj = decoder.readObject();
      decoder.close();
    } catch (FileNotFoundException e) {
      // imprime erro na console
      System.out.println(e.getMessage());
    }
    return obj; // retorna o objeto lido do arquivo XML
  }
}


No próximo post vamos usar este formato, ok?

sábado, 20 de outubro de 2012

Layout Manager e Netbeans

Tive uma pergunta em um post anterior solicitando que eu colocasse como utilizar os gerenciadores de layout via Netbeans. Fiz um pequeno vídeo mostrando a criação da mesma classe (não tive preocupação com colocar os mesmos nomes, mas está com os mesmos tipos de objetos).

Espero que gostem....


quinta-feira, 11 de outubro de 2012

Enviar email usando SMTP - parte II

Vamos agora apresentar uma classe simples para os testes e os resultados da execução


/*
 * classe de teste
 */

package testeenvioemail;

/**
 *
 * @author Henrique
 */

public class TesteEnvioEmail {

    /**
     * @param args não utilizado
     */

    public static void main(String[] args) {
        /*
         * Cria o remetente cadastrando dados do usuário, senha, host etc
         *
         */

        EmailRemetente rmt = new EmailRemetente();
        rmt.setUsuarioNome("Henrique Moura");
        rmt.setUsuarioEmail("COLOQUE AQUI SEU EMAIL");
        rmt.setSenha("A SENHA DO PROVEDOR PARA SEU USUÁRIO");
        rmt.setNomeHost("ENDEREÇO DO SERVIDOR SMTP");
        rmt.setPortaAlternativa(); // no meu caso preciso usar a porta 587
       
         /*
          * cria a mensagem composta por
          * 1) destinatario
          * 2) assunto
          * 3) corpo
         */

        EmailMensagem msg = new EmailMensagem();
        msg.setDestinatario("ENDEREÇO DE EMAIL PARA TESTES", "Henrique");
        msg.setAssunto("Assunto da mensagem - teste");
        msg.setCorpo("teste de mensagem enviada por email... via java");
       
        try {
           
            /*
             * prepara e envia o email
             */

            EnviarEmail email = new EnviarEmail(rmt, msg);
                       
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
   }
}


No Netbeans você deve configurar as bibliotecas para tudo funcionar:



Vamos ver a saída do programa:
run:
DEBUG: JavaMail version 1.4.5
DEBUG: successfully loaded resource: /META-INF/javamail.default.providers
DEBUG: Tables of loaded providers
DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Sun Microsystems, Inc], com.sun.mail.smtp.SMTPTransport=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Sun Microsystems, Inc], com.sun.mail.imap.IMAPSSLStore=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Sun Microsystems, Inc], com.sun.mail.pop3.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Sun Microsystems, Inc], com.sun.mail.imap.IMAPStore=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Sun Microsystems, Inc], com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Sun Microsystems, Inc]}
DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Sun Microsystems, Inc], imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Sun Microsystems, Inc], smtps=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Sun Microsystems, Inc], pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Sun Microsystems, Inc], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Sun Microsystems, Inc], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Sun Microsystems, Inc]}
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: setDebug: JavaMail version 1.4.5
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Sun Microsystems, Inc]
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "smtp.fournet.inf.br", port 587, isSSL false
220 parodius.seven.com.br ESMTP Postfix
DEBUG SMTP: connected to host "smtp.fournet.inf.br", port: 587

EHLO 192.168.0.113
250-SERVIDOR SELECIONADO
250-PIPELINING
250-SIZE 31457280
250-ETRN
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250-ENHANCEDSTATUSCODES
250 8BITMIME
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "SIZE", arg "31457280"
DEBUG SMTP: Found extension "ETRN", arg ""
DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN"
DEBUG SMTP: Found extension "AUTH=LOGIN", arg "PLAIN"
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Attempt to authenticate
DEBUG SMTP: check mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM
DEBUG SMTP: AUTH LOGIN command trace suppressed
DEBUG SMTP: AUTH LOGIN succeeded
DEBUG SMTP: use8bit false
MAIL FROM:<EMAIL DO REMETENTE>
250 2.1.0 Ok
RCPT TO:<EMAIL DO DESTINATÁRIO>
250 2.1.5 Ok
DEBUG SMTP: Verified Addresses
DEBUG SMTP:   EMAIL DO DESTINATÁRIO
DATA
354 End data with <CR><LF>.<CR><LF>
From: Henrique Moura <
EMAIL DO REMETENTE>
To:
EMAIL DO DESTINATÁRIOMessage-ID: <29930061.0.1350336137396.JavaMail.Henrique@Henrique-PC>
Subject: Assunto da mensagem - teste
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

teste de mensagem... via java
.
250 2.0.0 Ok: queued as 4B73B95D53
QUIT
221 2.0.0 Bye
CONSTRUÍDO COM SUCESSO (tempo total: 4 segundos)

Se você rodar o código conforme está neste post e no anterior, a primeira dúvida que vai surgir na sua cabeça é: como é que está aparecendo este tanto de linhas de debug na tela? É que na verdade eu acrescentei duas linhas dentro da classe EnviarEmail somente para que vocês vissem as mensagens. Estas mensagens ajudar a descobrir algum erro, como por exemplo autenticação, porta errada etc. As linhas que coloquei são:
  • props.put("mail.debug", "true");
  • session.setDebug(true);
A linha em verde acima também só vai aparecer se você estiver rodando no Netbeans. É uma informação da IDE sobre o tempo de montagem e compilação das classes no arquivo JAR.

Você agora pode incrementar as classes:
  • colocando autenticação para SSL e TLS;
  • pode colocar anexos;
  • pode colocar múltiplos destinatários;
  • etc.


Sem as linhas de debug ao rodar o programa você vai ter somente:
run:
CONSTRUÍDO COM SUCESSO (tempo total: 4 segundos)

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.