Páginas

terça-feira, 5 de junho de 2012

Enviando E-Mail com Java

Nesta postagem vamos ver como enviar e-mail, incluindo formato multipart, anexos e imagens incorporadas, dentre outras configurações úteis.
Existem algumas APIs de e-mail disponíveis, e dentre elas uma que se destaca na comunidade é a Commons Mail da Apache, mas aqui iremos nos dedicar a API JavaMail que é disponibilizada pela Oracle.

Ambiente

Para este tutorial o ambiente utilizado possui as seguintes configurações:
- Java SE 1.6.0_31
- JavaMail API 1.4.5
Atenção! Caso você esteja codificando com um Java SE 1.5 ou menor é necessário incluir o JavaBeans Activation Framework em seu classpath (verifique o arquivo readme.txt incluso com o download do JavaMail).

Preparando a sessão

A primeira parte do código deve se preocupar em preparar a sessão de e-mail, responsável pela negociação com o servidor de envio. No caso, o servidor de envio será através de protocolo SMTP.
// Armazena as propriedades da sessão
Properties props = new Properties();
// Propriedades de conexão smtp
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.host", "endereco.seu.servidor.smtp");
Session session = null;
Authenticator authenticator = null;
// Verifica se o envio é autenticado
if(ehSMTPAutenticado()) {
 // Propriedade de autenticação de envio
 props.put("mail.smtp.auth", "true");
 // Um autenticador simples
 authenticator = new Authenticator() {
  @Override
  protected PasswordAuthentication getPasswordAuthentication() {
   return new PasswordAuthentication("usuariosmtp", "senhausuariosmtp");
  }
 };
}
session = Session.getDefaultInstance(props, authenticator);
// debug? mostra mensagens de debug
session.setDebug(true);
Verifique neste trecho de código que, caso seu servidor de envio necessite de usuário autenticado será fornecido um autenticador para o construtor de sessão de e-mail. Este autenticador pode ser melhorado para interagir com o usuário e solicitar login e senha.
As mensagens de debug estão habilitadas na última linha deste trecho, não esqueça de desativar estas mensagens ao colocar seu código em produção.

Preparando a mensagem

Vamos criar uma mensagem tipo MIME (Multipurpose Internet Mail Extensions), o formato mais comum e com suporte a multipart.
// Preparando uma mensagem com base na sessão
MimeMessage message = new MimeMessage(session);

O remetente

Para mensagens preparadas a partir de uma sessão autenticada, o remetente será recuperado das informações de autenticação, enquanto sessões não autenticadas não possuirão remetente previamente definido.
Indiferente a configuração da sessão, você pode alterar as informações do remetente:
// Remetente
message.setFrom(new InternetAddress("Eu <eu@nos.com>"));
// Responder para
message.setReplyTo(new InternetAddress[]{ new InternetAddress("Não responda <no-reply@nos.com>")});
Neste trecho observe o uso da classe de construção de endereço de e-mail InternetAddress, os formatos possíveis de serem utilizados são:
- "user@server.com": formato simples somente com o endereço de e-mail;
- "User da Silva <user@server.com>": formato detalhado com nome para exibição.
A informação de "responder para" é comumente utilizada em aplicativos com envio automático de e-mail que não deve ser respondido pelo destinatário, basta atribuir um endereço inválido e mesmo que o usuário teime em mandar uma resposta ele receberá um retorno de impossibilidade de envio. Normalmente, quando se utiliza este recurso, o remetente (setFrom) também é definido com um endereço inválido. Repare que é possível definir diversos endereços no "responder para".

O destinatário

Adicionar um ou mais destinatários para a sua mensagem é simples e segue o padrão do remetente, a principal diferença é a indicação do campo de inclusão de cada destinatário:
// Destinatário PARA (principal)
message.addRecipient(Message.RecipientType.TO, new InternetAddress("Você <voce@nos.com>"));
// Destinatário CC (cópia)
message.addRecipient(Message.RecipientType.CC, new InternetAddress("Tu <tu@nos.com>"));
// Destinatário BCC (cópia oculta)
message.addRecipient(Message.RecipientType.BCC, new InternetAddress("Ele <ele@nos.com>"));
Caso prefira, ao invés de utilizar o método add para cada destinatário, a API também disponibiliza métodos set que recebem informações agrupadas.

O conteúdo da mensagem

// Definir assunto da mensagem
message.setSubject("Nossa mensagem em JavaMail", "iso-8859-1");
// Criar tipo de mensagem multipart para permitir inclusão de anexos
Multipart mpCorpoPrincipal = new MimeMultipart("related");
A definição do assunto (setSubject) de uma mensagem deve ser feita no charset US-ASCII, então nós passamos o nosso charset de trabalho para a correta conversão de caracteres. Iremos definir o charset em uso sempre que possível para evitar qualquer contratempo com conversão de caracteres.
O subtipo de mensagem "related" indica que iremos construir uma mensagem feita de diversos pedaços que se relacionam, permitindo a inclusão de imagens que faremos depois.

Inserindo o corpo

Vamos criar o corpo do e-mail com subtipo "alternative" para permitir que visualizadores de e-mail sem suporte a html consigam exibir um texto limpo, sem os caracteres que compõem as tags html, aos usuários.
// Criando corpo da mensagem (com texto e html)
MimeMultipart mpContent = new MimeMultipart("alternative");
// A raiz para agrupar os dois tipos de textos
MimeBodyPart corpoRaiz = new MimeBodyPart();
corpoRaiz.setContent(mpContent);
// Adiciona a raiz à mensagem
mpCorpoPrincipal.addBodyPart(corpoRaiz);

// Adicionando texto puro à raiz
MimeBodyPart mbpTextPlain = new MimeBodyPart();
mbpTextPlain.setText("Seja bem vindo ao JavaMail", "iso-8859-1", "plain");
mpContent.addBodyPart(mbpTextPlain);
// Adicionando texto html à raiz
MimeBodyPart mbpTextHtml = new MimeBodyPart();
mbpTextHtml.setText("Seja bem vindo ao <b>JavaMail<\b><br><img src=\"cid:img1\">", "iso-8859-1", "html");
mpContent.addBodyPart(mbpTextHtml);
Através desta estrutura de criação do corpo da mensagem os visualizadores de e-mail serão capazes de exibir o formato mais adequado as suas capacidades. Caso o visualizador seja moderno irá mostrar a mensagem em html, caso contrário irá mostrar a mensagem em texto puro. É importante ressaltar que a responsabilidade pelo conteúdo de cada pedaço de mensagem é responsabilidade da aplicação, e não da API; caso seja inserida informação html no texto puro, estas informações não serão removidas e serão exibidas como código fonte para o usuário.
No trecho html, note a tag img, iremos analisar esta parte mais a frente.

Anexos

Adicionar anexos não possui segredo, basta ter a referência ao arquivo que será anexado:
// Obtém a referência ao arquivo
File f = new File("algumarquivo.txt");
// Cria a parte de e-mail para anexo e adiciona o arquivo
MimeBodyPart mbpAnexo = new MimeBodyPart();
mbpAnexo.setDisposition(Part.ATTACHMENT);
mbpAnexo.setDataHandler(new DataHandler(new FileDataSource(f)));
mbpAnexo.setFileName(f.getName());
// Insere na mensagem
mpCorpoPrincipal.addBodyPart(mbpAnexo);

Imagens incorporadas

Lembrando que se desejar apenas enviar uma imagem como anexo, utilize a estrutura acima, nesta parte iremos incluir imagens que poderão ser utilizadas pela parte html da mensagem.
// Obtém a referência ao arquivo de imagem
File f = new File("suaimagem.png");
// Cria a parte de e-mail que irá armazenar a imagem e adiciona o arquivo
MimeBodyPart mbpImagemInline = new MimeBodyPart();
mbpImagemInline.setDataHandler(new DataHandler(new FileDataSource(f)));
mbpImagemInline.setFileName(f.getName());
// Define um id que pode ser utilizado no html
mbpImagemInline.setHeader("Content-ID", "<img1>");
// Insere na mensagem
mpCorpoPrincipal.addBodyPart(mbpImagemInline);
Neste trecho é importante definir o "Content-ID", para cada imagem, que foi definido da parte html da mensagem mais acima, em conjunto com o protocolo "cid", este é o atributo de vínculo que será utilizado para incorporar a imagem no local correto.

Finalmente, enviando

// Define o conteúdo na mensagem
message.setContent(mpCorpoPrincipal);
// Envia a mensagem
Transport.send(message);?
Sem necessidade de comentário especiais neste trecho de código. Apenas fecha o pacote e envia o e-mail.

Recursos

JavaMail API http://www.oracle.com/technetwork/java/javamail/index.html
Apache Commons Email http://commons.apache.org/email/
MIME http://en.wikipedia.org/wiki/MIME

Nenhum comentário:

Postar um comentário

Olá! Antes de postar seu comentário, por favor, observe que comentários técnicos, elogios e sugestões são antecipadamente agradecidos, esclarecimentos sobre os conceitos envolvidos na postagem serão respondidos da melhor forma possível, mas pedidos de ajuda técnica ou suporte individual deverão ser feitos através do formulário de contato. Grato!