package com.example.firstapp.utils.mail
|
|
import android.text.Html
|
import android.text.Spanned
|
import com.example.firstapp.utils.Log
|
import org.bouncycastle.openpgp.PGPPublicKeyRing
|
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
import java.io.File
|
import java.security.PrivateKey
|
import java.security.cert.X509Certificate
|
import java.util.Properties
|
import javax.mail.Authenticator
|
import javax.mail.PasswordAuthentication
|
|
@Suppress("PrivatePropertyName", "DEPRECATION")
|
class EmailSender(
|
// SMTP参数
|
private val host: String, // SMTP服务器地址
|
private val port: String, // SMTP服务器端口
|
private val from: String, // 发件人邮箱
|
private val password: String, // 发件人邮箱密码/授权码
|
// 邮件参数
|
private val nickname: String, // 发件人昵称
|
private val subject: String, // 邮件主题
|
private val body: CharSequence, // 邮件正文
|
private val attachFiles: MutableList<File> = mutableListOf(), // 附件
|
// 收件人参数
|
private val toAddress: MutableList<String> = mutableListOf(), // 收件人邮箱
|
private val ccAddress: MutableList<String> = mutableListOf(), // 抄送者邮箱
|
private val bccAddress: MutableList<String> = mutableListOf(), // 密送者邮箱
|
// 监听器
|
private val listener: EmailTaskListener? = null,
|
// 安全选项
|
private val openSSL: Boolean = false, //是否开启ssl验证 默认关闭
|
private val sslFactory: String = "javax.net.ssl.SSLSocketFactory", //SSL构建类名
|
private val startTls: Boolean = false, //是否开启starttls加密方式 默认关闭
|
// 邮件加密方式: S/MIME、OpenPGP、Plain(不传证书)
|
private val encryptionProtocol: String = "S/MIME",
|
// 邮件 S/MIME 加密和签名
|
private val recipientX509Cert: X509Certificate? = null, //收件人公钥(用于加密)
|
private val senderPrivateKey: PrivateKey? = null, //发件人私玥(用于签名)
|
private val senderX509Cert: X509Certificate? = null, //发件人公玥(用于签名)
|
//邮件 PGP 加密和签名
|
private var recipientPGPPublicKeyRing: PGPPublicKeyRing? = null, // 收件人公钥(用于加密)
|
private var senderPGPSecretKeyRing: PGPSecretKeyRing? = null, // 发件人私钥(用于签名)
|
private val senderPGPSecretKeyPassword: String = "", // 发件人私钥密码
|
) {
|
|
private val TAG: String = EmailSender::class.java.simpleName
|
|
private val properties: Properties = Properties().apply {
|
// 设置邮件服务器的主机名
|
put("mail.smtp.host", host)
|
// 设置邮件服务器的端口号
|
put("mail.smtp.port", port)
|
// 设置是否需要身份验证
|
put("mail.smtp.auth", "true")
|
// 设置是否启用 SSL 连接
|
if (openSSL) {
|
put("mail.smtp.ssl.enable", "true")
|
put("mail.smtp.socketFactory.class", sslFactory)
|
}
|
// 设置是否启用 TLS 连接
|
if (startTls) {
|
put("mail.smtp.starttls.enable", "true")
|
}
|
}
|
|
suspend fun sendEmail() {
|
try {
|
val authenticator = MailAuthenticator(from, password)
|
// 邮件正文
|
val html = try {
|
if (body is Spanned) Html.toHtml(body) else body.toString()
|
} catch (e: Exception) {
|
body.toString()
|
}
|
|
// 发送 S/MIME 邮件
|
when (encryptionProtocol) {
|
"S/MIME" -> {
|
val smimeUtils = SmimeUtils(
|
properties,
|
authenticator,
|
from,
|
nickname,
|
subject,
|
html,
|
attachFiles,
|
toAddress,
|
ccAddress,
|
bccAddress,
|
recipientX509Cert,
|
senderPrivateKey,
|
senderX509Cert,
|
)
|
val isEncrypt: Boolean = recipientX509Cert != null
|
val isSign: Boolean = senderX509Cert != null && senderPrivateKey != null
|
Log.d(TAG, "isEncrypt=$isEncrypt, isSign=$isSign")
|
val result = when {
|
isEncrypt && isSign -> smimeUtils.sendSignedAndEncryptedEmail()
|
isEncrypt -> smimeUtils.sendEncryptedEmail()
|
isSign -> smimeUtils.sendSignedEmail()
|
else -> smimeUtils.sendPlainEmail()
|
}
|
listener?.onEmailSent(result.first, result.second)
|
}
|
|
"OpenPGP" -> {
|
// 发送 PGP 邮件
|
val pgpEmail = PgpUtils(
|
properties,
|
authenticator,
|
from,
|
nickname,
|
subject,
|
html,
|
attachFiles,
|
toAddress,
|
ccAddress,
|
bccAddress,
|
recipientPGPPublicKeyRing,
|
senderPGPSecretKeyRing,
|
senderPGPSecretKeyPassword,
|
)
|
val isEncrypt: Boolean = recipientPGPPublicKeyRing != null
|
val isSign: Boolean = senderPGPSecretKeyRing != null
|
Log.d(TAG, "isEncrypt=$isEncrypt, isSign=$isSign")
|
val result = when {
|
isEncrypt && isSign -> pgpEmail.sendSignedAndEncryptedEmail()
|
isEncrypt -> pgpEmail.sendEncryptedEmail()
|
isSign -> pgpEmail.sendSignedEmail()
|
else -> pgpEmail.sendPlainEmail()
|
}
|
listener?.onEmailSent(result.first, result.second)
|
}
|
|
else -> {
|
// 发送普通邮件
|
val simpleEmail = SmimeUtils(
|
properties,
|
authenticator,
|
from,
|
nickname,
|
subject,
|
html,
|
attachFiles,
|
toAddress,
|
ccAddress,
|
bccAddress,
|
)
|
val result = simpleEmail.sendPlainEmail()
|
listener?.onEmailSent(result.first, result.second)
|
}
|
}
|
} catch (e: Exception) {
|
listener?.onEmailSent(false, "Error sending email: ${e.message}")
|
}
|
}
|
|
interface EmailTaskListener {
|
fun onEmailSent(success: Boolean, message: String)
|
}
|
|
/**
|
* 发件箱auth校验
|
*/
|
private class MailAuthenticator(username: String, private var password: String) : Authenticator() {
|
private var userName: String? = username
|
override fun getPasswordAuthentication(): PasswordAuthentication {
|
return PasswordAuthentication(userName, password)
|
}
|
}
|
}
|