在 Android 中使用 JavaMail API 发送电子邮件,而不使用默认/内置应用程序

Sending Email in Android using JavaMail API without using the default/built-in app

提问人:Vinayak Bevinakatti 提问时间:1/7/2010 最后编辑:Alireza SabahiVinayak Bevinakatti 更新时间:3/14/2023 访问量:474020

问:

我正在尝试在Android中创建一个邮件发送应用程序。

如果我使用:

Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);

这将启动内置的 Android 应用程序;我正在尝试在不使用此应用程序的情况下直接单击按钮发送邮件。

java 电子邮件 android-intent jakarta-mail

评论

3赞 T D Nguyen 1/19/2015
javax.mail.AuthenticationFailedException,但发送电子邮件时,用户/密码正确。有什么解决办法吗?
1赞 artbristol 3/25/2016
请注意,从 1.5.5 开始,JavaMail 声称支持 Android
1赞 Stamatis Stiliats 7/27/2017
SendGrid 不是一种选择吗?据我所知,您还可以获得有关您发送的 emai 的统计数据
0赞 Abhishek 7/9/2020
SendGrid 有一些尚未解决的 android 严重问题

答:

40赞 Kshitij Aggarwal 1/8/2010 #1

您可以使用 JavaMail API 来处理电子邮件任务。JavaMail API 在 JavaEE 包中可用,其 jar 可供下载。可悲的是,它不能直接在 Android 应用程序中使用,因为它使用了在 Android 中完全不兼容的 AWT 组件。

您可以在以下位置找到 JavaMail 的 Android 端口: http://code.google.com/p/javamail-android/

将 jar 添加到应用程序并使用 SMTP 方法

评论

1赞 user1050755 3/11/2014
有没有 maven 存储库?
0赞 Kshitij Aggarwal 3/11/2014
对不起,我不知道
6赞 artbristol 4/5/2015
我已经移植了最新的 JavaMail,它可以在 Maven Central 的eu.ocathain.com.sun.mail:javax.mail:1.5.2
24赞 Lena Schimmel 1/8/2010 #2

SMTP的

使用SMTP是一种方法,其他人已经指出了如何做到这一点的方法。请注意,在执行此操作时,您完全绕过了内置的邮件应用程序,并且您必须在代码中静态提供 SMTP 服务器的地址、该服务器的用户名和密码,或者从用户那里查询它。

HTTP协议

另一种方法是使用一个简单的服务器端脚本,如 php,它采用一些 URL 参数并使用它们来发送邮件。这样,您只需要从设备发出 HTTP 请求(使用内置库即可轻松实现),而无需在设备上存储 SMTP 登录数据。与直接使用SMTP相比,这是一种间接性,但是由于从PHP发出HTTP请求和发送邮件非常容易,因此它甚至可能比直接方式更简单。

邮件申请

如果邮件是从用户已经在手机上注册的用户默认邮件帐户发送的,则必须采取其他方法。如果您有足够的时间和经验,您可能需要检查 Android 电子邮件应用程序的源代码,看看它是否提供了一些入口点来发送邮件而无需用户交互(我不知道,但也许有一个)。

也许您甚至找到了一种方法来查询用户帐户详细信息(因此您可以将它们用于 SMTP),尽管我非常怀疑这是否可能,因为这将是一个巨大的安全风险,而且 Android 的构建相当安全。

789赞 Vinayak Bevinakatti 1/9/2010 #3

使用 Gmail 身份验证的 JavaMail API 在 Android 中发送电子邮件。

创建示例项目的步骤:

邮件发件人活动.java:

public class MailSenderActivity extends Activity {
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        final Button send = (Button) this.findViewById(R.id.send);
        send.setOnClickListener(new View.OnClickListener() {
            
            public void onClick(View v) {
                try {   
                    GMailSender sender = new GMailSender("[email protected]", "password");
                    sender.sendMail("This is Subject",   
                            "This is Body",   
                            "[email protected]",   
                            "[email protected]");   
                } catch (Exception e) {   
                    Log.e("SendMail", e.getMessage(), e);   
                } 
                
            }
        });
        
    }
}

GMailSender.java:

public class GMailSender extends javax.mail.Authenticator {   
    private String mailhost = "smtp.gmail.com";   
    private String user;   
    private String password;   
    private Session session;   
  
    static {   
        Security.addProvider(new com.provider.JSSEProvider());   
    }  
  
    public GMailSender(String user, String password) {   
        this.user = user;   
        this.password = password;   
  
        Properties props = new Properties();   
        props.setProperty("mail.transport.protocol", "smtp");   
        props.setProperty("mail.host", mailhost);   
        props.put("mail.smtp.auth", "true");   
        props.put("mail.smtp.port", "465");   
        props.put("mail.smtp.socketFactory.port", "465");   
        props.put("mail.smtp.socketFactory.class",   
                "javax.net.ssl.SSLSocketFactory");   
        props.put("mail.smtp.socketFactory.fallback", "false");   
        props.setProperty("mail.smtp.quitwait", "false");   
  
        session = Session.getDefaultInstance(props, this);   
    }   
  
    protected PasswordAuthentication getPasswordAuthentication() {   
        return new PasswordAuthentication(user, password);   
    }   
  
    public synchronized void sendMail(String subject, String body, String sender, String recipients) throws Exception {   
        try{
        MimeMessage message = new MimeMessage(session);   
        DataHandler handler = new DataHandler(new ByteArrayDataSource(body.getBytes(), "text/plain"));   
        message.setSender(new InternetAddress(sender));   
        message.setSubject(subject);   
        message.setDataHandler(handler);   
        if (recipients.indexOf(',') > 0)   
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipients));   
        else  
            message.setRecipient(Message.RecipientType.TO, new InternetAddress(recipients));   
        Transport.send(message);   
        }catch(Exception e){
            
        }
    }   
  
    public class ByteArrayDataSource implements DataSource {   
        private byte[] data;   
        private String type;   
  
        public ByteArrayDataSource(byte[] data, String type) {   
            super();   
            this.data = data;   
            this.type = type;   
        }   
  
        public ByteArrayDataSource(byte[] data) {   
            super();   
            this.data = data;   
        }   
  
        public void setType(String type) {   
            this.type = type;   
        }   
  
        public String getContentType() {   
            if (type == null)   
                return "application/octet-stream";   
            else  
                return type;   
        }   
  
        public InputStream getInputStream() throws IOException {   
            return new ByteArrayInputStream(data);   
        }   
  
        public String getName() {   
            return "ByteArrayDataSource";   
        }   
  
        public OutputStream getOutputStream() throws IOException {   
            throw new IOException("Not Supported");   
        }   
    }   
}  

JSSEProvider.java:

/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/**
 * @author Alexander Y. Kleymenov
 * @version $Revision$
 */


import java.security.AccessController;
import java.security.Provider;

public final class JSSEProvider extends Provider {

    public JSSEProvider() {
        super("HarmonyJSSE", 1.0, "Harmony JSSE Provider");
        AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() {
            public Void run() {
                put("SSLContext.TLS",
                        "org.apache.harmony.xnet.provider.jsse.SSLContextImpl");
                put("Alg.Alias.SSLContext.TLSv1", "TLS");
                put("KeyManagerFactory.X509",
                        "org.apache.harmony.xnet.provider.jsse.KeyManagerFactoryImpl");
                put("TrustManagerFactory.X509",
                        "org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl");
                return null;
            }
        });
    }
}

将以下三个 jar 添加到您的 Android 项目中。

如果您不知道如何操作,请查看这篇文章

不要忘记在清单中添加以下行:

<uses-permission android:name="android.permission.INTERNET" />

通过访问此链接,为安全性较低的应用调整帐户访问设置:

https://www.google.com/settings/security/lesssecureapps


UPD 2023:安全性较低的应用已被弃用。要访问您的帐户,您需要启用双重身份验证,并使用下图中提供的设置使用应用密码:

How to create Temporary Password


运行项目并检查邮件的收件人邮件帐户。

P.S.:请记住,不允许直接从 Android 中的 Activity 执行网络操作。因此,强烈建议使用或避免在主线程上遇到网络异常。AsyncTaskIntentService

Jar 文件:https://code.google.com/archive/p/javamail-android/

评论

56赞 Rich 9/24/2010
您的代码似乎使用硬编码的用户名和密码。这目前是否存在安全风险(这意味着,上传到市场的 apk 是否已被反编译)?
11赞 Avi Shukron 5/6/2011
为我工作!!不要忘记将 uses-permission INTERNET 添加到您的应用清单中
20赞 pumpkee 9/21/2011
有没有办法在不将密码放入代码的情况下发送电子邮件?我认为如果我向他们询问他们的电子邮件 pw,用户会感到震惊......
7赞 M.A.Murali 5/10/2012
嗨,感谢您的代码。但是我在 GMailSender sender = new GMailSender(...) on mailsenderactivity 上得到了 java.lang.NoClassDefFoundError。我包含了所有 jar 并添加了构建路径。我花了一些时间来解决它,但我没有得到解决方案。请帮帮我。
60赞 Tom 7/10/2012
对于那些抱怨/询问如何获取用户密码的人 - 这不是这里的想法。这旨在与您(开发人员的)电子邮件帐户一起使用。如果你想依赖用户的电子邮件帐户,你应该使用电子邮件意图,这在其他文章中被广泛讨论。
58赞 ManuV 5/17/2010 #4

无法连接到 SMTP 主机: smtp.gmail.com,端口:465

在清单中添加以下行:

<uses-permission android:name="android.permission.INTERNET" />
73赞 Krishna 4/26/2011 #5

感谢您提供宝贵的信息。代码工作正常。我也可以通过添加以下代码来添加附件。

private Multipart _multipart; 
_multipart = new MimeMultipart(); 

public void addAttachment(String filename,String subject) throws Exception { 
    BodyPart messageBodyPart = new MimeBodyPart(); 
    DataSource source = new FileDataSource(filename); 
    messageBodyPart.setDataHandler(new DataHandler(source)); 
    messageBodyPart.setFileName(filename); 
    _multipart.addBodyPart(messageBodyPart);

    BodyPart messageBodyPart2 = new MimeBodyPart(); 
    messageBodyPart2.setText(subject); 

    _multipart.addBodyPart(messageBodyPart2); 
} 



message.setContent(_multipart);

评论

6赞 Garbage 1/23/2013
将此添加到GmailSender .java
0赞 Calvin 8/19/2015
当我调用 setContent 时,它覆盖了我的正文内容。我做错了什么吗?我想添加带有其他文本正文内容的附件
1赞 11/9/2016
对于此处的变量,您必须指定文件路径。例如:filenameString path = Environment.getExternalStorageDirectory().getPath() + "/temp_share.jpg";
0赞 AndroidManifester 1/20/2020
此代码可帮助您添加多个文件 stackoverflow.com/a/3177640/2811343;) :)
23赞 droopie 10/19/2012 #6

这是一个 alt 版本,它也适用于我,并且有附件(已经在上面发布,但与源链接不同,完整的版本,人们发布后由于缺少数据而无法让它工作)

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.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 _from; 

  private String _port; 
  private String _sport; 

  private String _host; 

  private String _subject; 
  private String _body; 

  private boolean _auth; 

  private boolean _debuggable; 

  private Multipart _multipart; 


  public Mail() { 
    _host = "smtp.gmail.com"; // default smtp server 
    _port = "465"; // default smtp port 
    _sport = "465"; // default socketfactory port 

    _user = ""; // username 
    _pass = ""; // password 
    _from = ""; // email sent from 
    _subject = ""; // email subject 
    _body = ""; // email body 

    _debuggable = false; // debug mode on or off - default off 
    _auth = true; // smtp authentication - default on 

    _multipart = new MimeMultipart(); 

    // There is something wrong with MailCap, javamail can not find a handler for the multipart/mixed part, so this bit needs to be added. 
    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 Mail(String user, String pass) { 
    this(); 

    _user = user; 
    _pass = pass; 
  } 

  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); 

      msg.setSubject(_subject); 
      msg.setSentDate(new Date()); 

      // setup message body 
      BodyPart messageBodyPart = new MimeBodyPart(); 
      messageBodyPart.setText(_body); 
      _multipart.addBodyPart(messageBodyPart); 

      // Put parts in message 
      msg.setContent(_multipart); 

      // send email 
      Transport.send(msg); 

      return true; 
    } else { 
      return false; 
    } 
  } 

  public void addAttachment(String filename) throws Exception { 
    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); 

    if(_debuggable) { 
      props.put("mail.debug", "true"); 
    } 

    if(_auth) { 
      props.put("mail.smtp.auth", "true"); 
    } 

    props.put("mail.smtp.port", _port); 
    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) {
      // TODO Auto-generated method stub
      this._to=toArr;
  }

  public void setFrom(String string) {
      // TODO Auto-generated method stub
      this._from=string;
  }

  public void setSubject(String string) {
      // TODO Auto-generated method stub
      this._subject=string;
  }  

  // more of the getters and setters ….. 
}

并在活动中调用它......

@Override 
public void onCreate(Bundle icicle) { 
  super.onCreate(icicle); 
  setContentView(R.layout.main); 

  Button addImage = (Button) findViewById(R.id.send_email); 
  addImage.setOnClickListener(new View.OnClickListener() { 
    public void onClick(View view) { 
      Mail m = new Mail("[email protected]", "password"); 

      String[] toArr = {"[email protected]", "[email protected]"}; 
      m.setTo(toArr); 
      m.setFrom("[email protected]"); 
      m.setSubject("This is an email sent using my Mail JavaMail wrapper from an Android device."); 
      m.setBody("Email body."); 

      try { 
        m.addAttachment("/sdcard/filelocation"); 

        if(m.send()) { 
          Toast.makeText(MailApp.this, "Email was sent successfully.", Toast.LENGTH_LONG).show(); 
        } else { 
          Toast.makeText(MailApp.this, "Email was not sent.", Toast.LENGTH_LONG).show(); 
        } 
      } catch(Exception e) { 
        //Toast.makeText(MailApp.this, "There was a problem sending the email.", Toast.LENGTH_LONG).show(); 
        Log.e("MailApp", "Could not send email", e); 
      } 
    } 
  }); 
} 

评论

0赞 0xC0DED00D 11/11/2013
@KeyLimePiePhotonAndroid 向清单添加 Internet 权限
0赞 roger_that 3/19/2014
如果我想使用任何其他电子邮件客户端,例如我的组织,如何使用此代码?仅更改主机名和端口就足够了吗?
0赞 T D Nguyen 1/19/2015
javax.mail.AuthenticationFailedException适用于Android 4.4.4的任何解决方案?
2赞 Razel Soco 2/4/2016
对于 javax.mail.AuthenticationFailedException ,您需要 google.com/settings/security/lesssecureapps
1赞 jgrocha 6/12/2016
要解决,有必要看到这个解决方案 stackoverflow.com/questions/25093546/...Could not send email android.os.NetworkOnMainThreadException at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork
31赞 Ryan Heitner 11/20/2012 #7

为了帮助那些使用 SDK 目标 >9 获得主线程网络异常的人。这是使用上面的 droopie 代码,但对任何代码都类似。

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();

StrictMode.setThreadPolicy(policy); 

android.os.NetworkOnMainThreadException

您可以使用 AsyncTask,如下所示

public void onClickMail(View view) {
    new SendEmailAsyncTask().execute();
}

class SendEmailAsyncTask extends AsyncTask <Void, Void, Boolean> {
    Mail m = new Mail("[email protected]", "my password");

    public SendEmailAsyncTask() {
        if (BuildConfig.DEBUG) Log.v(SendEmailAsyncTask.class.getName(), "SendEmailAsyncTask()");
        String[] toArr = { "to [email protected]"};
        m.setTo(toArr);
        m.setFrom("from [email protected]");
        m.setSubject("Email from Android");
        m.setBody("body.");
    }

    @Override
    protected Boolean doInBackground(Void... params) {
        if (BuildConfig.DEBUG) Log.v(SendEmailAsyncTask.class.getName(), "doInBackground()");
        try {
            m.send();
            return true;
        } catch (AuthenticationFailedException e) {
            Log.e(SendEmailAsyncTask.class.getName(), "Bad account details");
            e.printStackTrace();
            return false;
        } catch (MessagingException e) {
            Log.e(SendEmailAsyncTask.class.getName(), m.getTo(null) + "failed");
            e.printStackTrace();
            return false;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
3赞 Anthony Dahanne 6/18/2013 #8

您是否考虑过使用Apache Commons Net?从 3.3 开始,只需一个 jar(您可以使用 gradle 或 maven 依赖它)即可完成:http://blog.dahanne.net/2013/06/17/sending-a-mail-in-java-and-android-with-apache-commons-net/

0赞 dhiraj kakran 2/25/2014 #9
 Add jar files mail.jar,activation.jar,additionnal.jar

 String sub="Thank you for your online registration" ; 
 Mail m = new Mail("emailid", "password"); 

 String[] toArr = {"[email protected]",sEmailId};
 m.setFrom("[email protected]"); 

     m.setTo(toArr);
     m.setSubject(sub);
    m.setBody(msg);



                     try{


                            if(m.send()) { 

                            } else { 

                            } 
                          } catch(Exception e) { 

                            Log.e("MailApp", "Could not send email", e); 
                          } 

  package com.example.ekktra;

   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.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 _from; 

     private String _port; 
     private String _sport; 

     private String _host; 

     private String _subject; 
     private String _body; 

     private boolean _auth; 

     private boolean _debuggable; 

     private Multipart _multipart; 


   public Mail() { 
      _host = "smtp.gmail.com"; // default smtp server 
      _port = "465"; // default smtp port 
      _sport = "465"; // default socketfactory port 

      _user = ""; // username 
      _pass = ""; // password 
      _from = ""; // email sent from 
      _subject = ""; // email subject 
      _body = ""; // email body 

      _debuggable = false; // debug mode on or off - default off 
      _auth = true; // smtp authentication - default on 

      _multipart = new MimeMultipart(); 

      // There is something wrong with MailCap, javamail can not find a handler for the        multipart/mixed part, so this bit needs to be added. 
      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 Mail(String user, String pass) { 
  this(); 

  _user = user; 
   _pass = pass; 
 } 

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); 

    msg.setSubject(_subject); 
    msg.setSentDate(new Date()); 

  // setup message body 
  BodyPart messageBodyPart = new MimeBodyPart(); 
    messageBodyPart.setText(_body); 
    _multipart.addBodyPart(messageBodyPart); 

     // Put parts in message 
    msg.setContent(_multipart); 

    // send email 
    Transport.send(msg); 

    return true; 
   } else { 
     return false; 
   } 
  } 

   public void addAttachment(String filename) throws Exception { 
    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); 

  if(_debuggable) { 
    props.put("mail.debug", "true"); 
  } 

  if(_auth) { 
    props.put("mail.smtp.auth", "true"); 
   } 

    props.put("mail.smtp.port", _port); 
    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) {
     // TODO Auto-generated method stub
    this._to=toArr;
 }

public void setFrom(String string) {
    // TODO Auto-generated method stub
    this._from=string;
}

 public void setSubject(String string) {
    // TODO Auto-generated method stub
    this._subject=string;
  }  


   }
4赞 Rashid 5/6/2014 #10

用于发送带有附件的邮件。

public class SendAttachment{
                    public static void main(String [] args){ 
             //to address
                    String to="[email protected]";//change accordingly
                    //from address
                    final String user="[email protected]";//change accordingly
                    final String password="password";//change accordingly 
                     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); 
                  //1) get the session object   
                  Properties properties = System.getProperties();
                  properties.put("mail.smtp.port", "465"); 
                  properties.put("mail.smtp.host", "smtp.gmail.com");
                    properties.put("mail.smtp.socketFactory.port", "465");
                    properties.put("mail.smtp.socketFactory.class",
                            "javax.net.ssl.SSLSocketFactory");
                    properties.put("mail.smtp.auth", "true");
                    properties.put("mail.smtp.port", "465");

                  Session session = Session.getDefaultInstance(properties,
                   new javax.mail.Authenticator() {
                   protected PasswordAuthentication getPasswordAuthentication() {
                   return new PasswordAuthentication(user,password);
                   }
                  });

                  //2) compose message   
                  try{ 
                    MimeMessage message = new MimeMessage(session);
                    message.setFrom(new InternetAddress(user));
                    message.addRecipient(Message.RecipientType.TO,new InternetAddress(to));
                    message.setSubject("Hii"); 
                    //3) create MimeBodyPart object and set your message content    
                    BodyPart messageBodyPart1 = new MimeBodyPart();
                    messageBodyPart1.setText("How is This"); 
                    //4) create new MimeBodyPart object and set DataHandler object to this object    
                    MimeBodyPart messageBodyPart2 = new MimeBodyPart();
                //Location of file to be attached
                    String filename = Environment.getExternalStorageDirectory().getPath()+"/R2832.zip";//change accordingly
                    DataSource source = new FileDataSource(filename);
                    messageBodyPart2.setDataHandler(new DataHandler(source));
                    messageBodyPart2.setFileName("Hello"); 
                    //5) create Multipart object and add MimeBodyPart objects to this object    
                    Multipart multipart = new MimeMultipart();
                    multipart.addBodyPart(messageBodyPart1);
                    multipart.addBodyPart(messageBodyPart2); 
                    //6) set the multiplart object to the message object
                    message.setContent(multipart ); 
                    //7) send message 
                    Transport.send(message); 
                   System.out.println("MESSAGE SENT....");
                   }catch (MessagingException ex) {ex.printStackTrace();}
                  }
                }

评论

0赞 Rashid 5/6/2014
添加 jar 文件激活.jar , additionnal.jar , javax.mail.jar
1赞 kodartcha 5/13/2014
尝试您的方法时出现以下错误:05-13 11:51:50.454:E/AndroidRuntime(4273):android.os.NetworkOnMainThreadException 05-13 11:51:50.454:E/AndroidRuntime(4273):在android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1156)。我有互联网权限。有什么建议吗?
1赞 Rashid 5/13/2014
尝试在线程中调用该方法...这是一个耗时的过程......它不能在主线程上运行...
0赞 Syamantak Basu 5/22/2014
我在我的Android项目中完全使用此代码,邮件对我来说工作正常。但是附件部分不起作用。我正在尝试附加 .txt 文件。但是收到的邮件包含无法打开的未知类型的文件。请帮忙。
0赞 Syamantak Basu 5/22/2014
@Rashid当然是我做到了。当我以前使用 Intent 时,我的附件是正确的。
14赞 Mark 6/9/2014 #11

如果使用“smtp.gmail.com”作为默认 smtp 服务器,则发出警告。

Google会强迫您经常更改链接的电子邮件帐户密码,因为他们过于热心的“可疑活动”政策。从本质上讲,它将在短时间内来自不同国家的重复 smtp 请求视为“可疑活动”。正如他们假设的那样,您(电子邮件帐户持有人)一次只能在一个国家/地区。

当谷歌系统检测到“可疑活动”时,它将阻止进一步的电子邮件,直到您更改密码。由于您将密码硬编码到应用程序中,因此每次发生这种情况时都必须重新发布应用程序,这并不理想。这在一周内发生在我身上 3 次,我什至将密码存储在另一台服务器上,并在每次谷歌强迫我更改密码时动态获取密码。

因此,我建议使用众多免费的 smtp 提供程序之一而不是“smtp.gmail.com”来避免此安全问题。使用相同的代码,但将“smtp.gmail.com”更改为新的 smtp 转发主机。

评论

2赞 Paulo Matuki 11/11/2014
这是一个很好的观点。但是,您能否举例说明使用代码的备用电子邮件提供商(仅替换 smtp 和登录详细信息)。我用 hushmail 和 email.com 尝试过,但没有成功。会继续与他人一起尝试。
0赞 Wesley 3/24/2015
@PauloMatuki,@Mark,嗨,你们解决问题了吗?suspicioud activity
3赞 ngrashia 7/30/2014 #12

无需用户干预,您可以按如下方式发送:

  1. 从客户端发送电子邮件 apk.这里 mail.jar,需要激活 .jar 才能发送 java 电子邮件。如果添加这些 jar,可能会增加 APK 大小。

  2. 或者,您可以在服务器端代码中使用 Web 服务,它将使用相同的 mail.jar 和激活 .jar 来发送电子邮件。您可以通过 asynctask 调用 Web 服务并发送电子邮件。请参阅同一链接。

(但是,您需要知道邮件帐户的凭据)

2赞 Zephyr 9/27/2014 #13

如果要求将 jar 库保持尽可能小,可以单独包含 SMTP/POP3/IMAP 函数,以避免“dex 中的方法太多”问题。

您可以从javanet网页中选择所需的jar库,例如mailapi.jar + imap.jar可以让您访问icloud,IMAP协议中的hotmail邮件服务器。(借助额外的.jar和激活.jar)

5赞 Omkar Gokhale 12/1/2014 #14

那些尝试将三个 jar 文件移动到您项目的 lib 文件夹的人,它对我有用!!ClassDefNotFoundError

2赞 NoSixties 2/24/2015 #15

我尝试使用 @Vinayak B 提交的代码。但是我收到一个错误,说:没有 smtp 的提供程序

我为此创建了一个新问题,其中包含更多信息 这里

毕竟,我能够自己修复它。我不得不使用其他邮件.jar,并且必须确保我的“访问不太安全的应用程序”已打开。

我希望这对任何有同样问题的人有所帮助。完成此操作后,这段代码也可以在谷歌眼镜上运行。

8赞 artbristol 4/5/2015 #16

编辑:JavaMail 1.5.5声称支持Android,因此您不需要其他任何东西。

我已将最新的 JavaMail (1.5.4) 移植到 Android。在 Maven Central 中可用,只需在 build.gradle 中添加以下内容即可~~

compile 'eu.ocathain.com.sun.mail:javax.mail:1.5.4'

然后,您可以按照官方教程进行操作。

源代码可在此处获得: https://bitbucket.org/artbristol/javamail-forked-android

评论

0赞 wrapperapps 12/2/2015
那个 Maven/Gradle 行对我不起作用。从您的 Bitbucket 下载 1.5.4 也不适合我。它与常规的非 Android javamail 在同一行失败,即 MimeMessage.setText(text)。
0赞 artbristol 1/23/2016
听到这个消息@wrapperapps很遗憾。“它对我有用!”随意在 bitbucket 存储库上提出问题
4赞 Patriotic 10/7/2015 #17

我无法运行 Vinayak B 的代码。最后,我通过以下方式解决了这个问题:

1.使用这个

2.应用 AsyncTask。

3.更改发件人Gmail帐户的安全问题。(更改为“TURN ON”) 在此

2赞 Enrichman 6/23/2016 #18

其他答案中提供的所有代码都是正确的,工作正常,但有点混乱,所以我决定发布一个库(尽管仍在开发中)以更简单的方式使用它:AndroidMail

你只需要创建一个 MailSender,构建一个邮件并发送它(已经在后台使用 AsyncTask 处理)。

MailSender mailSender = new MailSender(email, password);

Mail.MailBuilder builder = new Mail.MailBuilder();
Mail mail = builder
    .setSender(senderMail)
    .addRecipient(new Recipient(recipient))
    .setText("Hello")
    .build();

mailSender.sendMail(mail);

您可以收到已发送电子邮件的通知,它还支持不同的收件人类型(收件人、抄送和密件抄送)、附件和 html:

MailSender mailSender = new MailSender(email, password);

Mail.MailBuilder builder = new Mail.MailBuilder();
Mail mail = builder
    .setSender(senderMail)
    .addRecipient(new Recipient(recipient))
    .addRecipient(new Recipient(Recipient.TYPE.CC, recipientCC))
    .setText("Hello")
    .setHtml("<h1 style=\"color:red;\">Hello</h1>")
    .addAttachment(new Attachment(filePath, fileName))
    .build();

mailSender.sendMail(mail, new MailSender.OnMailSentListener() {

    @Override
    public void onSuccess() {
        // mail sent!
    }

    @Override
    public void onError(Exception error) {
        // something bad happened :(
    }
});

您可以通过 Gradle 或 Maven 获取它:

compile 'it.enricocandino:androidmail:1.0.0-SNAPSHOT'

如果您有任何问题,请告诉我!:)

-3赞 della raharjo 11/1/2016 #19

要添加附件,请不要忘记添加。

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);
18赞 S.R 6/15/2017 #20

GmailBackground 是一个小型库,无需用户交互即可在后台发送电子邮件:

用法:

    BackgroundMail.newBuilder(this)
            .withUsername("[email protected]")
            .withPassword("password12345")
            .withMailto("[email protected]")
            .withType(BackgroundMail.TYPE_PLAIN)
            .withSubject("this is the subject")
            .withBody("this is the body")
            .withOnSuccessCallback(new BackgroundMail.OnSuccessCallback() {
                @Override
                public void onSuccess() {
                    //do some magic
                }
            })
            .withOnFailCallback(new BackgroundMail.OnFailCallback() {
                @Override
                public void onFail() {
                    //do some magic
                }
            })
            .send();

配置:

repositories {
    // ...
    maven { url "https://jitpack.io" }
 }
 dependencies {
            compile 'com.github.yesidlazaro:GmailBackground:1.2.0'
    }

权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>

此外,对于附件,您需要设置READ_EXTERNAL_STORAGE权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

(我自己测试过)

评论

0赞 Erich García 4/22/2018
我使用它并且工作完美。但是我做了一些修改,以便将其与不同的电子邮件提供商一起使用,当向Gmail发送电子邮件时,它返回我“发件人”标题丢失了......如何解决?
0赞 Jawad Malik 9/20/2019
您好,我在我的应用程序中使用此 api,但它不起作用并且总是调用 onfailcallback
8赞 Shreshth Kharbanda 2/18/2018 #21

我为其他需要帮助的人找到了一个更短的选择。代码为:

package com.example.mail;

import java.util.Properties;

import javax.mail.Message;
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;

public class SendMailTLS {

    public static void main(String[] args) {

        final String username = "[email protected]";
        final String password = "password";

        Properties props = new Properties();
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.host", "smtp.gmail.com");
        props.put("mail.smtp.port", "587");

        Session session = Session.getInstance(props,
          new javax.mail.Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
          });

        try {

            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress("[email protected]"));
            message.setRecipients(Message.RecipientType.TO,
                InternetAddress.parse("[email protected]"));
            message.setSubject("Testing Subject");
            message.setText("Dear Mail Crawler,"
                + "\n\n No spam to my email, please!");

            Transport.send(message);

            System.out.println("Done");

        } catch (MessagingException e) {
            throw new RuntimeException(e);
        }
    }
}

来源:通过 JavaMail API 发送电子邮件

希望这有帮助!祝你好运!

1赞 Blundell 2/6/2020 #22

使用 Kotlin 以编程方式发送电子邮件。

  • 简单的电子邮件发送,而不是所有其他功能(如附件)。
  • TLS 始终处于开启状态
  • 也只需要 1 个 gradle 电子邮件依赖项。

我还发现这个电子邮件 POP 服务列表真的很有帮助:

https://support.office.com/en-gb/article/pop-and-imap-email-settings-for-outlook-8361e398-8af4-4e97-b147-6c6c4ac95353

如何使用:

    val auth = EmailService.UserPassAuthenticator("[email protected]", "yourPassword")
    val to = listOf(InternetAddress("[email protected]"))
    val from = InternetAddress("[email protected]")
    val email = EmailService.Email(auth, to, from, "Test Subject", "Hello Body World")
    val emailService = EmailService("smtp.gmail.com", 465)
    
    GlobalScope.launch { // or however you do background threads
        emailService.send(email)
    }

代码:

import java.util.*
import javax.mail.*
import javax.mail.internet.InternetAddress
import javax.mail.internet.MimeBodyPart
import javax.mail.internet.MimeMessage
import javax.mail.internet.MimeMultipart

class EmailService(private val server: String, private val port: Int) {

    data class Email(
        val auth: Authenticator,
        val toList: List<InternetAddress>,
        val from: Address,
        val subject: String,
        val body: String
    )

    class UserPassAuthenticator(private val username: String, private val password: String) : Authenticator() {
        override fun getPasswordAuthentication(): PasswordAuthentication {
            return PasswordAuthentication(username, password)
        }
    }

    fun send(email: Email) {
        val props = Properties()
        props["mail.smtp.auth"] = "true"
        props["mail.user"] = email.from
        props["mail.smtp.host"] = server
        props["mail.smtp.port"] = port
        props["mail.smtp.starttls.enable"] = "true"
        props["mail.smtp.ssl.trust"] = server
        props["mail.mime.charset"] = "UTF-8"
        val msg: Message = MimeMessage(Session.getDefaultInstance(props, email.auth))
        msg.setFrom(email.from)
        msg.sentDate = Calendar.getInstance().time
        msg.setRecipients(Message.RecipientType.TO, email.toList.toTypedArray())
//      msg.setRecipients(Message.RecipientType.CC, email.ccList.toTypedArray())
//      msg.setRecipients(Message.RecipientType.BCC, email.bccList.toTypedArray())
        msg.replyTo = arrayOf(email.from)

        msg.addHeader("X-Mailer", CLIENT_NAME)
        msg.addHeader("Precedence", "bulk")
        msg.subject = email.subject

        msg.setContent(MimeMultipart().apply {
            addBodyPart(MimeBodyPart().apply {
                setText(email.body, "iso-8859-1")
                //setContent(email.htmlBody, "text/html; charset=UTF-8")
            })
        })
        Transport.send(msg)
    }

    companion object {
        const val CLIENT_NAME = "Android StackOverflow programmatic email"
    }
}

Gradle:

dependencies {
    implementation 'com.sun.mail:android-mail:1.6.4'
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3"
}

Android清单:

<uses-permission android:name="android.permission.INTERNET" />
1赞 Nguyen Minh Hien 4/2/2020 #23

这里有很多解决方案。但是,我认为我们必须更改 GMail 的配置,以允许从安全性较低的设备进行访问。转到下面的链接并启用它。它对我有用

https://myaccount.google.com/lesssecureapps?pli=1

0赞 Andrew 6/20/2020 #24

对于那些想在 2020 年将 JavaMail 与 Kotlin 一起使用的人:

首先:将这些依赖项添加到您的 build.gradle 文件中(官方 JavaMail Maven 依赖项)

实现“com.sun.mail:android-mail:1.6.5”

实现'com.sun.mail:android-activation:1.6.5'

实现 “org.bouncycastle:bcmail-jdk15on:1.65”

实现 “org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7”

实现 “org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7”

BouncyCastle是出于安全原因。

第二:将这些权限添加到您的 AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

第三:使用SMTP时,创建一个配置文件

object Config {
    const val EMAIL_FROM = "[email protected]"
    const val PASS_FROM = "Your_Sender_Password"

    const val EMAIL_TO = "[email protected]"
}

第四:创建你的邮件程序对象

object Mailer {

init {
    Security.addProvider(BouncyCastleProvider())
}

private fun props(): Properties = Properties().also {
        // Smtp server
        it["mail.smtp.host"] = "smtp.gmail.com"
        // Change when necessary
        it["mail.smtp.auth"] = "true"
        it["mail.smtp.port"] = "465"
        // Easy and fast way to enable ssl in JavaMail
        it["mail.smtp.ssl.enable"] = true
    }

// Dont ever use "getDefaultInstance" like other examples do!
private fun session(emailFrom: String, emailPass: String): Session = Session.getInstance(props(), object : Authenticator() {
    override fun getPasswordAuthentication(): PasswordAuthentication {
        return PasswordAuthentication(emailFrom, emailPass)
    }
})

private fun builtMessage(firstName: String, surName: String): String {
    return """
            <b>Name:</b> $firstName  <br/>
            <b>Surname:</b> $surName <br/>
        """.trimIndent()
}

private fun builtSubject(issue: String, firstName: String, surName: String):String {
    return """
            $issue | $firstName, $surName
        """.trimIndent()
}

private fun sendMessageTo(emailFrom: String, session: Session, message: String, subject: String) {
    try {
        MimeMessage(session).let { mime ->
            mime.setFrom(InternetAddress(emailFrom))
            // Adding receiver
            mime.addRecipient(Message.RecipientType.TO, InternetAddress(Config.EMAIL_TO))
            // Adding subject
            mime.subject = subject
            // Adding message
            mime.setText(message)
            // Set Content of Message to Html if needed
            mime.setContent(message, "text/html")
            // send mail
            Transport.send(mime)
        }

    } catch (e: MessagingException) {
        Log.e("","") // Or use timber, it really doesn't matter
    }
}

fun sendMail(firstName: String, surName: String) {
        // Open a session
        val session = session(Config.EMAIL_FROM, Config.PASSWORD_FROM)

        // Create a message
        val message = builtMessage(firstName, surName)

        // Create subject
        val subject = builtSubject(firstName, surName)

        // Send Email
        CoroutineScope(Dispatchers.IO).launch { sendMessageTo(Config.EMAIL_FROM, session, message, subject) }
}

注意

0赞 Rishita Joshi 2/4/2022 #25
package io.formics.tourguide

import android.annotation.SuppressLint
import android.content.Intent
import android.net.Credentials
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_feedback.*
import org.jetbrains.annotations.Async
import java.lang.Exception

import java.util.Properties;


import javax.activation.DataHandler;
import javax.activation.FileDataSource
import javax.mail.*
import javax.mail.internet.*


class FeedbackActivity : AppCompatActivity()  {
  
    val props = Properties()


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_feedback)

        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.host", "smtp.gmail.com");
        props.put("mail.smtp.port", "587");

        btnSendEmail.setOnClickListener {
            Thread {
                try {
                    sendEmail()
                    // Your implementation
                } catch (ex: Exception) {
                    ex.printStackTrace()
                }
            }.start()


        }
    }


    private fun sendEmail() {



        try {

            val session = Session.getInstance(props,
                object : javax.mail.Authenticator() {
                    //Authenticating the password
                    override fun getPasswordAuthentication(): javax.mail.PasswordAuthentication {
                        return PasswordAuthentication("[email protected]", "password")
                    }
                })

            val message = MimeMessage(session);
            message.setFrom(InternetAddress("[email protected]"));
            message.setRecipients(
                Message.RecipientType.TO,
                InternetAddress.parse(editCC.text.toString())
            )
            message.subject = editSubject.text.toString()
            message.setText(
                "Dear Mail Crawler,"
                        + "\n\n No spam to my email, please!"
            );

            //val messageBodyPart = MimeBodyPart();

            //val multipart = MimeMultipart();

            //val file = "path of file to be attached";

//            val fileName = "attachmentName"
           // val source = FileDataSource(file);
            //messageBodyPart.setDataHandler(DataHandler(source));
            //messageBodyPart.setFileName(fileName);
            //multipart.addBodyPart(messageBodyPart);

            //message.setContent(multipart);

            Transport.send(message);
            System.out.println("Done");



        } catch (e: MessagingException) {
            throw  RuntimeException(e);
        }

           }
}