All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xyz.cssxsh.mirai.admin.mail.MailDsl.kt Maven / Gradle / Ivy

@file:JvmName("BuildKt")

package xyz.cssxsh.mirai.admin.mail

import jakarta.activation.*
import jakarta.mail.*
import jakarta.mail.internet.*
import java.io.*
import java.nio.file.*
import java.util.*

/**
 * [Environment Properties](https://jakarta.ee/specifications/mail/2.1/jakarta-mail-spec-2.1.html#a823)
 */
public fun buildMailSession(block: Properties.() -> Unit): Session {
    val props = Properties(System.getProperties())
    val current = Thread.currentThread()
    val oc = current.contextClassLoader
    try {
        block.invoke(props)
    } finally {
        current.contextClassLoader = oc
    }

    if (props.getProperty("mail.smtp.localhost") == null) {
        props.setProperty("mail.smtp.localhost", props.getProperty("mail.host"))
    }

    val auth = PropsAuthenticator(props = props)

    return try {
        current.contextClassLoader = block::class.java.classLoader
        Session.getDefaultInstance(props, auth)
    } finally {
        current.contextClassLoader = oc
    }
}

/**
 * 构建邮件
 * @see MailContentBuilder
 */
public fun buildMailContent(session: Session, block: MailContentBuilder.(MimeMessage) -> Unit): MimeMessage {
    val message = MimeMessage(session)
    val builder: MailContentBuilder

    val current = Thread.currentThread()
    val oc = current.contextClassLoader
    try {
        current.contextClassLoader = block::class.java.classLoader
        builder = MailContentBuilder(session)
        block.invoke(builder, message)

        message.setFrom(builder.from)

        message.setRecipients(MimeMessage.RecipientType.TO, builder.to)

        if (builder.title.isEmpty()) throw throw IllegalArgumentException("title is empty")
        message.setSubject(builder.title, "UTF-8")

        if (builder.content.count == 0) throw throw IllegalArgumentException("content is empty")
        message.setContent(builder.content)

    } finally {
        current.contextClassLoader = oc
    }

    return message
}

@DslMarker
public annotation class MailDsl

public class MailContentBuilder(session: Session) {
    @MailDsl
    public var from: String? = session.getProperty("mail.from")

    @MailDsl
    public var to: String? = null

    @MailDsl
    public var title: String = ""

    @MailDsl
    public var content: MimeMultipart = MimeMultipart()

    @MailDsl
    public fun text(type: String = "plain", builderAction: StringBuilder.() -> Unit) {
        val part = MimeBodyPart()
        val text = StringBuilder().apply(builderAction).toString()
        part.setText(text, "UTF-8", type)
        content.addBodyPart(part)
    }

    @MailDsl
    public fun file(filename: String? = null, builderAction: () -> Any?) {
        val part = MimeBodyPart()
        when (val target = builderAction()) {
            is File -> {
                part.dataHandler = DataHandler(FileDataSource(target))
                part.fileName = filename ?: target.name
            }
            is Path -> {
                val file = target.toFile()
                part.dataHandler = DataHandler(FileDataSource(file))
                part.fileName = filename ?: file.name
            }
            is DataSource -> {
                part.dataHandler = DataHandler(target)
                part.fileName = filename ?: target.name ?: "data.bin"
            }
            is DataHandler -> {
                part.dataHandler = target
                part.fileName = filename ?: target.name ?: "data.bin"
            }
            is String -> {
                val file = File(target)
                part.dataHandler = DataHandler(FileDataSource(file))
                part.fileName = filename ?: file.name
            }
            Unit, null -> return
            else -> throw IllegalArgumentException("file")
        }
        content.addBodyPart(part)
    }
}

@PublishedApi
internal class PropsAuthenticator(private val props: Properties) : Authenticator() {
    override fun getPasswordAuthentication(): PasswordAuthentication {
        val user = props["mail.${requestingProtocol}.user"]?.toString()
            ?: props["mail.user"]?.toString()
            ?: System.getenv("MAIL_USER")
            ?: throw NoSuchElementException("mail.user")
        val password = props["mail.${requestingProtocol}.password"]?.toString()
            ?: props["mail.password"]?.toString()
            ?: System.getenv("MAIL_PASSWORD")
            ?: throw NoSuchElementException("mail.password")
        return PasswordAuthentication(user, password)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy