Hoje vou ensinar como você pode enviar emails através de um app Android.
Diversos apps Android que desenvolvi para empresas como LG, Embelleze e Renault necessitavam que, após o usuário usar o app, que a interação fosse enviada por email para o próprio usuário e/ou para a empresa dona do app. Essa interação podia ser o preenchimento de um formulário, uma foto tirada com o app, as respostas de um quiz, etc.
Para exemplificar vamos criar uma tela que pede o nome e email de uma pessoa, e quando ela clicar em um botão no final do formulário, vamos enviar um email para ela. Se você nunca fez um app Android antes, recomendo a leitura deste ebook bem curtinho.
O layout XML da tela, chamada aqui de activity_main.xml, segue abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="16dp" android:paddingRight="16dp" android:paddingTop="16dp" android:paddingBottom="16dp" android:background="#981a43" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:textAppearance="?android:attr/textAppearanceLarge" android:text="Nome:" android:textColor="@android:color/white" android:textStyle="bold" android:id="@+id/lblNome" /> <EditText android:layout_width="match_parent" android:layout_height="60dp" android:inputType="textPersonName" android:layout_marginTop="10dp" android:textColor="@android:color/white" android:ems="10" android:id="@+id/txtNome" android:layout_below="@+id/lblNome" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@android:color/white" android:textStyle="bold" android:textAppearance="?android:attr/textAppearanceLarge" android:text="E-mail:" android:layout_marginTop="20dp" android:layout_below="@+id/txtNome" android:id="@+id/lblEmail" /> <EditText android:layout_width="match_parent" android:layout_height="60dp" android:inputType="textEmailAddress" android:layout_marginTop="10dp" android:layout_below="@+id/lblEmail" android:textColor="@android:color/white" android:ems="10" android:id="@+id/txtEmail" /> <Button android:layout_width="120dp" android:layout_height="60dp" android:text="Enviar email" android:layout_below="@+id/txtEmail" android:id="@+id/btnEmail" /> </RelativeLayout> |
Isso deve gerar uma interface como abaixo:
Agora, na activity por trás dessa tela, chamada de MainActivity, temos de adicionar o código do evento de clique desse botão, que chama um método de envio de email.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends AppCompatActivity { EditText txtNome, txtEmail; Button btnEmail; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtNome = (EditText)findViewById(R.id.txtNome); txtEmail = (EditText)findViewById(R.id.txtEmail); btnEmail = (Button)findViewById(R.id.btnEmail); btnEmail.setOnClickListener(new Button.OnClickListener(){ @Override public void onClick(View v) { enviarEmail(); } }); } } |
O método enviarEmail chamado no clique do botão anterior deve ler os campos informados pelo usuário (nome e email), verificar se o smartphone está conectado na Internet (afinal, se não estiver vai dar erro no envio do email) e depois envia o dito cujo usando uma outra classe Java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
private void enviarEmail(){ final String nome = txtNome.getText().toString(); final String email = txtEmail.getText().toString(); final String subject = "assunto do email"; final String body = "corpo do email do " + nome; if(!isOnline()) { Toast.makeText(getApplicationContext(), "Não estava online para enviar e-mail!", Toast.LENGTH_SHORT).show(); System.exit(0); } new Thread(new Runnable(){ @Override public void run() { Mail m = new Mail(); String[] toArr = {email}; m.setTo(toArr); //m.setFrom("[email protected]"); //caso queira enviar em nome de outro m.setSubject(subject); m.setBody(body); try { //m.addAttachment("pathDoAnexo");//anexo opcional m.send(); } catch(RuntimeException rex){ }//erro ignorado catch(Exception e) { e.printStackTrace(); System.exit(0); } Toast.makeText(getApplicationContext(), "Email enviado!", Toast.LENGTH_SHORT).show(); } }).start(); } |
Note que me preocupei em realizar o envio do email em uma thread separada, como manda as guidelines do Android, evitando que a tela fique travada durante o envio, o que pode demorar alguns segundos dependendo da sua conexão com a Internet e do seu provedor de email.
Também incluí um comentário contendo o código para adicionar um anexo, que apenas precisa da URI de um arquivo armazenado no seu dispositivo.
A classe Mail utilizada no exemplo anterior foi encontrada na Internet há vários anos atrás e se mostrou bem confiável. Não lembro o quanto já customizei ela, mas de qualquer forma segue abaixo a versão mais atual que possuo, na íntegra (crie ela em outro arquivo de classe Java).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
package br.com.luiztools.envioemail; import java.util.Date; import java.util.Properties; import javax.activation.CommandMap; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.activation.MailcapCommandMap; import javax.mail.BodyPart; import javax.mail.Message; import javax.mail.Multipart; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; public class Mail extends javax.mail.Authenticator { private String _user; private String _pass; private String[] _to; private String[] _cco; private String _from; private String _port; private String _sport; private String _host; private String _subject; private String _body; private boolean _auth; private boolean _useSsl; private boolean _isHtmlBody; private boolean _debuggable; private Multipart _multipart; public Mail() { _host = "smtp.umbler.com"; _port = "587"; // porta de envio, geralmente 587, 465 ou em último caso a 25 _sport = "587"; // porta socket padrão, mesmas instruções anteriores _pass = ""; // senha _subject = ""; // assunto _body = ""; // mensagem html _debuggable = false; _auth = true; _useSsl = false;//gmail usa true _isHtmlBody = true;//diz se a mensagem é HTML ou texto puro _multipart = new MimeMultipart(); MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap(); mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html"); mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml"); mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain"); mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed"); mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822"); CommandMap.setDefaultCommandMap(mc); } public boolean send() throws Exception { Properties props = _setProperties(); if(!_user.equals("") && !_pass.equals("") && _to.length > 0 && !_from.equals("") && !_subject.equals("") && !_body.equals("")) { Session session = Session.getInstance(props, this); MimeMessage msg = new MimeMessage(session); msg.setFrom(new InternetAddress(_from)); InternetAddress[] addressTo = new InternetAddress[_to.length]; for (int i = 0; i < _to.length; i++) { addressTo[i] = new InternetAddress(_to[i]); } msg.setRecipients(MimeMessage.RecipientType.TO, addressTo); //se tem de enviar cópia oculta para alguém if(_cco != null && _cco.length > 0) { InternetAddress[] addressCco = new InternetAddress[_cco.length]; for(int i=0; i < _cco.length; i++){ addressCco[i] = new InternetAddress(_cco[i]); } msg.addRecipients(Message.RecipientType.BCC, addressCco); } msg.setSubject(_subject); msg.setSentDate(new Date()); // corpo da mensagem BodyPart messageBodyPart = new MimeBodyPart(); messageBodyPart.setText(_body); if(_isHtmlBody) { messageBodyPart.setHeader("charset", "utf-8"); messageBodyPart.setHeader("content-type", "text/html"); } _multipart.addBodyPart(messageBodyPart); msg.setContent(_multipart); // envia o email Transport.send(msg); return true; } else { return false; } } public void addAttachment(String filename) throws Exception { filename = filename.replace("file:","").replace("//","/"); BodyPart messageBodyPart = new MimeBodyPart(); DataSource source = new FileDataSource(filename); messageBodyPart.setDataHandler(new DataHandler(source)); messageBodyPart.setFileName(filename); _multipart.addBodyPart(messageBodyPart); } @Override public PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(_user, _pass); } private Properties _setProperties() { Properties props = new Properties(); props.put("mail.smtp.host", _host); props.put("mail.smtp.port", _port); if(_debuggable) props.put("mail.debug", "true"); if(_auth) props.put("mail.smtp.auth", "true"); if(_useSsl) { props.put("mail.smtp.socketFactory.port", _sport); props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.put("mail.smtp.socketFactory.fallback", "false"); } return props; } // the getters and setters public String getBody() { return _body; } public void setBody(String _body) { this._body = _body; } public void setTo(String[] toArr) { this._to=toArr; } public void setCco(String[] ccoArr){ this._cco = ccoArr; } public void setFrom(String string) { this._from=string; } public void setSubject(String string) { this._subject=string; } } |
Aqui você deve prestar atenção no construtor vazio da classe Mail para colocar as configurações do seu servidor, como host SMTP, porta SMTP, se vai usar SSL, usuário e senha do seu email, etc.
Caso você nunca tenha enviado um email via software antes, é necessário que você se autentique em algum servidor de email com um usuário e senha válidos para poder enviar emails em seu nome. Ou seja, você vai ter de descobrir as configurações SMTP do seu provedor de email, além de saber o seu usuário (o próprio email) e senha (sua senha) para autenticação. São aquelas mesmas configurações usadas para o Outlook, sabe? Essas informações podem ser facilmente encontradas na Internet se seu email for Gmail, Hotmail, etc. Caso contrário consulte a empresa que lhe fornece emails (ex. Umbler) para obter as configurações de envio.
Para que essa classe funcione você vai precisar adicionar 3 bibliotecas Java ao seu projeto, que disponibilizo nesse zip. Basta descompactar e colocar os arquivos na pasta libs do seu projeto de app e pela IDE (normalmente o Android Studio) ir até a pasta libs e com o botão direito selecionar a opção ‘Add as library’ ou semelhante.
E para encerrar o que é necessário para que o código de envio de email funcione, falta criarmos o método isOnline() na MainActivity.java, responsável por testar a conexão com a Internet, pré-requisito para envio de email, conforme abaixo.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public boolean isOnline() { try { ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = cm.getActiveNetworkInfo(); return netInfo != null && netInfo.isConnectedOrConnecting(); } catch(Exception ex){ Toast.makeText(getApplicationContext(), "Erro ao verificar se estava online! (" + ex.getMessage() + ")", Toast.LENGTH_SHORT).show(); return false; } } |
Como estamos mexendo com recursos de hardware como Internet, conexão, etc. precisamos pedir essas permissões em nosso AndroidManifest.xml como abaixo.
1 2 3 4 5 |
<uses-permission android:name="android.permission.INTERNET"></uses-permission> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission> |
E se for usar anexos, não esqueça de adicionar também a permissão de leitura de arquivos.
Isso deve ser o suficiente para que você consiga enviar emails a partir desse app bem simples para o email informado no formulário a primeira tela. Esses códigos podem ser usados em apps maiores que fazem outras coisas e onde você apenas usará essa lógica para avisar alguém ou enviar uma mensagem. Daí a parte da criatividade eu deixo com você. 😉
Dica Avançada
Se seu app for utilizado por muitos usuários e/ou tiver um volume de envio de emails muito grande, procure usar soluções profissionais de SMTP Gateway como AWS SES, SendGrid e Mailgun. Jamais confie nos serviços de contas de email fornecido por provedores de hospedagem pois elas são configuradas para pequenos envios, jamais para envios em lote e rapidamente seu provedor irá bloquear a conta de email que seu app usa se enviar muitas mensagens por hora.
O SendGrid inclusive tem um plano gratuito em que você pode enviar 100 mensagens por dia de graça.
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.
Meus parabéns! E muito obrigado pois me serviu na faculdade.
não é android ou é muito velho
É Android, mas é um tutorial de muitos anos atrás, de quando eu ainda programava Android.