Pular para o conteúdo principal

JavaMail: Enviando mensagem HTML com anexos

Introdução

Depois do post "JavaMail: Enviando e-mail com Java", que apresentava como enviar um e-mail com Java, resolvi complementar a assunto apresentando como enviar uma mensagem formatada, em HTML, e também como realizar o envio de anexos.

Bibliotecas

Além da biblioteca JavaMail, veja mais no post anterior, é necessário incluir o JavaBeans Activation Framework (JAF), apenas se a versão utilizada for anterior ao JSE 6.0, que já tem o JAF incluso.
O JAF está disponível em http://www.oracle.com/technetwork/java/javase/downloads/index-135046.html, e neste download encontramos, alguns exemplos na pasta demo, documentação, incluindo javadocs, na pasta docs e a biblioteca activation.jar, que deve ser acrescentada no classpath da aplicação para versões anteriores ao JSE 6.0.

Exemplo

Primeiramente devemos realizar a configuração da javax.mail.Session e da javax.mail.internet.MimeMessage, estes passos podem ser vistos no post anterior.
Agora vamos montar uma mensagem HTML em uma String:
String htmlMessage = "< h t m l > Código HTML da mensagem </ h t m l >";
Para configurarmos a mensagem com os anexos (partes da mensagem), precisamos utilizar um objeto javax.mail.internet.MimeMultipart, que será formado por várias partes (javax.mail.internet.MimeBodyPart) e para tanto vamos instanciá-lo conforme segue:
Multipart multipart = new MimeMultipart();
A primeira parte da MimeMultipart, será a mensagem em HTML, então vamos criar e configurar um objeto javax.mail.internet.MimeBodyPart que representa uma parte da mensagem e adicioná-lo ao multipart:
MimeBodyPart attachment0 = new MimeBodyPart();
attachment0.setContent(htmlMessage,"text/html; charset=UTF-8");
multipart.addBodyPart(attachment0);
Observe que utilizamos o método setContent passando a String com a mensagem HTML e outra passando o mime type da mensagem "text/html; charset=UTF-8".

No nosso exemplo a segunda parte da MimeMultipart, será uma imagem, então criaremos um java.io.File referenciando o arquivo desejado.
String pathname = "duke.png";//pode conter o caminho
File file = new File(pathname);
Então criaremos mais um MimeBodyPart para a imagem que será anexada, para tanto faremos uso das classes javax.activation.FileDataSource e javax.activation.DataHandler do JAF, que realizarão o trabalho pesado de leitura, descoberta e configuração do tipo do arquivo, para inclusão do anexo.
MimeBodyPart attachment1 = new MimeBodyPart();
attachment1.setDataHandler(new DataHandler(new FileDataSource(file)));
attachment1.setFileName(file.getName());
multipart.addBodyPart(attachment1);
Vale observar que o nome do anexo não precisa ser necessariamente o mesmo do arquivo, visto que, conforme apresentado no código anterior, esta configuração é feita por meio do método setName, então para configurar com outro nome qualquer, bastaria utilizar o referido método da seguinte forma:
attachment1.setFileName("outroNomeQualquer.png");
Então, após adicionar todas as partes desejadas na javax.mail.internet.MimeMultipart , por meio do método addBodyPart basta adicioná-la como conteúdo da javax.mail.internet.MimeMessage e então efetivamente enviar a mensagem, como pode ser visto no trecho de código abaixo:
message.setContent(multipart);
Transport.send(message);

MailSenderPlus.java

Segue o código completo da classe que envia um e-mail com mensagem formatada e anexo.
package br.eti.castro.blog.samples.email;

//imports omitidos

public class MailSenderPlus {
 //o tratamento de excessoes foi simplificado (throws MessagingException)
 //para facilitar o entendimento do exemplo
 public static void main(String[] args) throws MessagingException{
  //objeto para definicao das propriedades de configuracao do provider
  Properties props = new Properties();
  //o valor "smtp.host.com.br" deve ser alterado para o seu servidor SMTP
  props.put("mail.host","smtp.host.com.br"); 
  //obtendo um Session com a configuração 
  //do servidor SMTP definida em props
  Session session = Session.getDefaultInstance(props);
  
  //criando a mensagem
  MimeMessage message = new MimeMessage(session);

  //substituir pelos e-mails desejados
  Address from = new InternetAddress("remetente@host.com");
  Address to = new InternetAddress("destinatario@host.com");

  //configurando o remetente e o destinatario
  message.setFrom(from);
  message.addRecipient(RecipientType.TO, to);

   //configurando a data de envio,  o assunto e o texto da mensagem
  message.setSentDate(new Date());
  message.setSubject("Enviando uma mensagem formatada com anexo");
  
  // conteudo html que sera atribuido a mensagem
  String htmlMessage = "< h t m l > Código HTML da mensagem ";

  //criando a Multipart
  Multipart multipart = new MimeMultipart();

  //criando a primeira parte da mensagem
  MimeBodyPart attachment0 = new MimeBodyPart();
  //configurando o htmlMessage com o mime type
  attachment0.setContent(htmlMessage,"text/html; charset=UTF-8");
  //adicionando na multipart
  multipart.addBodyPart(attachment0);
  
  //arquivo que será anexado
  String pathname = "duke.png";//pode conter o caminho
  File file = new File(pathname);

  //criando a segunda parte da mensagem
  MimeBodyPart attachment1 = new MimeBodyPart();  
  //configurando o DataHandler para o arquivo desejado
  //a leitura dos bytes, descoberta e configuracao do tipo
  //do arquivo serão resolvidos pelo JAF (DataHandler e FileDataSource)
  attachment1.setDataHandler(new DataHandler(new FileDataSource(file)));
  //configurando o nome do arquivo que pode ser diferente do arquivo
  //original Ex: setFileName("outroNome.png")
  attachment1.setFileName(file.getName());
  //adicionando o anexo na multipart
  multipart.addBodyPart(attachment1);

  //adicionando a multipart como conteudo da mensagem 
  message.setContent(multipart);
  
  //enviando
  Transport.send(message);
  
  System.out.println("E-mail enviado com sucesso!");
 }
}

E para finalizar me repito, afinal nunca é demais alertar, não use para enviar uma grande quantidade de mensagens em um curto de período de tempo, pois seu endereço, domínio ou IP podem cair em uma balcklist, e seus e-mails serem classificados como SPAM.

Até mais!
Marcelo de Castro
http://blog.castro.eti.br
http://twitter.com/mcastroinfo
http://www.globalcode.com.br/instrutores/MarceloCastro
Outros posts: http://blog.globalcode.com.br/search/label/MarceloCastro

Comentários

O Cotidiano disse…
Bom dia, estou usando esse exemplo que você disponibilizou e implementei para enviar 2 anexos. O problema é que vai os dois anexos, porém um é sempre 0 byte...

Teria algum exemplo que nãoocorre isso?
Ana Abrantes disse…
Como você fez?
Para incluir outro anexo, basta repetir o trecho que cria um novo MimeBodyPart e adiciona ao objeto multipart.
[]s
Ana
Unknown disse…
Muito bom ... Parabéns e obrigado!!!
Felipe disse…
Ola fiz um formulário simples de texto e quero criar apenas um anexo mas dá erro poderia me ajudar? Código está todo pronto, só não consigo implementar bendito do anexo.
Unknown disse…
estou tendo esse erro e sim, adicionei as bibliotecas

java.lang.NoClassDefFoundError: com/sun/mail/util/PropUtil

Postagens mais visitadas deste blog

10 reasons why we love JSF

1. One-slide technology: it's so simple that I can explain basic JSF with one slide. 2. Easy to extend: components, listeners, render kit, Events, Controller, etc. 3. Real-world adoption: JBoss, Exadel, Oracle, IBM, ... 4. Architecture model: you can choose between more than 100 different architecture. 5. Open-mind community: using JSF you are going to meet very interesting people. 6. We are using JSF the last 5 years and we found very good market for JSF in Brazil 7. Progress: look to JSf 1.1 to JSF 1.2, JSF 1.2 to JSF 2.0. People are working really hard! 8. Many professionals now available 9. It's a standard. It's JCP. Before complain, report and help! 10. Ed Burns, spec leader, is an old Globalcode community friend! EXTRA: My wife is specialist in JSF. She's my F1 for JSF :) Nice job JSF community! -Vinicius Senger

Transmissão do minicurso Google App Engine

Os minicursos gratuitos realizados através da iniciativa Open4Education da Globalcode têm sido transmitidos ao vivo em forma de webcast e eu tenho acompanhado pessoalmente muitos deles, conversado com os alunos no chat, observando a qualidade e as limitações das transmissões. Sem dúvida o aproveitamento presencial é muito maior, principalmente pelo networking e pelo foco dado ao conteúdo. Mas, para aqueles que não estão em São Paulo o custo benefício é sensacional. Mesmo perdendo um pouco nas transmissões, é muito melhor poder assistir os minicursos à distância. Com o sucesso das transmissões do Profissão Java e do The Developer's Conference 2010 queremos melhorar e atingir um público ainda maior, e é por isto, que iremos fazer a primeira transmissão ao vivo em parceria com a WTV Streaming hoje! Os principais benefícios desta parceria são: Transmissão do vídeo e não apenas do conteúdo que está sendo projetado Captação e edição do conteúdo, para posterior disponibilizaç...

Brasil e a força de trabalho: Futuro incerto

Mais de 70 mil brasileiros estariam empregados se tivessem formação em TI (...) Apesar do bom salário, este profissional tem se tornado artigo raro no Brasil, o que explica as vagas neste setor estarem entre as dez mais difíceis de serem preenchidas (...) MDIC (Ministério do Desenvolvimento, Indústria e Comércio Exterior) vai avaliar carência de profissionais de TI no país (...) O presidente do Confea admitiu, no entanto, que, no curto e no médio prazo, parte das vagas terá de ser ocupada por profissionais do exterior porque o país não terá como suprir as carências de imediato (...). Notícias como estas estão sendo veiculadas todo o tempo e há anos. Em novembro de 2010 postei em Globalcoder´s um artigo sobre esta mesma questão e, passados quase seis meses, parece-me que o cenário realmente mudou ... para pior. Assim como as notícias sobre este fato, temo também em tornar-me entediante com a minha abordagem insistente em destacar esta que considero uma verdadeira calamidade nac...

Sistema interativo de TV Digital com Ginga-J

No início de 2009, os estudantes de Sistema de Informação do Centro Universitário de Votuporanga ( UNIFEV ), Caio César Pereira de Souza e Rodrigo Gonçalves Constantino me apresentaram uma proposta para que eu fosse co-orientador junto ao professor orientador Djalma Domingos da Silva , em seu Trabalho de conclusão de curso (TCC) com tema TV Digital. A base que motivou o assunto, foi a palestra apresentada por Maurício Leal na I Conferência Java Noroeste sobre o tema TV Digital, realizada em 2006 em Votuporanga-SP. Ficamos muito entusiasmados com a possibilidade de interatividade na TV Digital, e a grande quantidade de possibilidades de desenvolvimento de aplicativos nesta área. Acompanhamos de perto as notícias na imprensa e todo o esforço e iniciativas realizadas pelo Fórum do Sistema Brasileiro de TV Digital Terrestre (SBTVD) , que organizou e produziu especificações ABNT, normatizando o sistema de TV Digital Terrestre. O foco do TCC foi realizar o desenvolvimento de uma pequena ...

Construindo um império com R$40,00

Algo que nós da  YaW temos nos dedicado com bastante afinco nos últimos meses é o Google AppEngine(GAE) . Para quem ainda não conhece, o GAE é um ambiente de runtime disponibilizado pelo Google onde você hospeda a sua aplicação sem precisar se preocupar com manutenção de servidores. E ainda ganha com tudo isso a escalabilidade proporcionada pelos servidores do próprio Google. Hoje ele dá suporte a duas linguagens: Python e Java(e a grande maioria dos seus frameworks de mercado como Struts 1 e Struts 2, JSF 1 e JSF 2, JPA com algumas limitações, EhCache, GWT, SpringMVC, etc. Lista completa aqui ). Um detalhe importante sobre o GAE é que de início ele é completamente gratuito, e possui uma quota(beeeem generosa) de utilização, a partir do momento que você ultrapassar esta quota você tem de pagar pelo que ultrapassou. Detalhes sobre as quotas aqui . O próprio site da YaW está hospedado no GAE. E o que isso tudo tem ha ver com os R$40,00 e o império que você quer cri...

Voucher Retake até 31/01

Um boa noticia para quem esta estudando para alguma certificação Java e precisa de um incentivo. Esta rolando a promoção do Voucher Retake para as certificações Java, Oracle Solaris (Cluster) e NetBeans, mas corram pois é apenas até 31/01. Para quem nunca ouviu falar do Voucher Retake, trata-se de um Voucher igual ao convencional que te permite fazer uma prova de certificação, mas com a possibilidade de refazê-la em caso de reprovação. E o período é o mesmo, ou seja, um ano para as duas tentativas. Com a Sun essa promoção já era esperada todo inicio de ano, mas como não sabemos qual será a estratégia da Oracle daqui pra frente então vale a pena aproveitar e divulgar. O local de compra é um "easter egg" dentro do site da Oracle, pois não esta tão acessível como deveria. Você precisa entrar no site: http://education.oracle.com, ai vai aparecer um banner no topo com três páginas, clique na terceira página onde haverá um link "comece agora" que direciona para página...