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

如果我使用:

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

这将启动内置的Android应用程序;我试图发送邮件按钮点击直接不使用这个应用程序。


当前回答

用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("you@gmail.com", "yourPassword")
    val to = listOf(InternetAddress("to@email.com"))
    val from = InternetAddress("you@gmail.com")
    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"
}

安卓清单:

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

其他回答

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

在清单中添加这一行:

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

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

用法:

    BackgroundMail.newBuilder(this)
            .withUsername("username@gmail.com")
            .withPassword("password12345")
            .withMailto("toemail@gmail.com")
            .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"/>

(我自己测试过)

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

创建示例项目的步骤:

MailSenderActivity.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("username@gmail.com", "password");
                    sender.sendMail("This is Subject",   
                            "This is Body",   
                            "user@gmail.com",   
                            "user@yahoo.com");   
                } 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;
            }
        });
    }
}

将下面链接中的3个罐子添加到你的Android项目中

mail.jar activation.jar additional.jar

点击这里-如何添加外部罐子

别忘了在你的清单上加上这一行:

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

只需点击下面的链接,更改帐户访问不太安全的应用程序 https://www.google.com/settings/security/lesssecureapps

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

另外,别忘了你不能在android的任何活动中进行网络操作。 因此,建议使用AsyncTask或IntentService来避免主线程网络异常。

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

为了帮助那些获得网络主线程异常与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("from@gmail.com", "my password");

    public SendEmailAsyncTask() {
        if (BuildConfig.DEBUG) Log.v(SendEmailAsyncTask.class.getName(), "SendEmailAsyncTask()");
        String[] toArr = { "to mail@gmail.com"};
        m.setTo(toArr);
        m.setFrom("from mail@gmail.com");
        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;
        }
    }

如果使用“smtp.gmail.com”作为默认的smtp服务器,请注意。

谷歌将迫使您更改您的链接电子邮件帐户密码频繁由于他们过于热心的“可疑活动”政策。本质上,它将短时间内来自不同国家的重复smtp请求视为“可疑活动”。因为他们假设你(电子邮件账户持有人)一次只能在一个国家。

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

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