-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
321 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
src/main/kotlin/xyz/cssxsh/mirai/admin/data/AdminMailConfig.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package xyz.cssxsh.mirai.admin.data | ||
|
||
import net.mamoe.mirai.console.command.* | ||
import net.mamoe.mirai.console.data.* | ||
import net.mamoe.mirai.console.plugin.* | ||
import net.mamoe.mirai.console.plugin.jvm.* | ||
import net.mamoe.mirai.console.util.* | ||
import net.mamoe.mirai.utils.* | ||
import java.io.* | ||
import kotlin.io.path.* | ||
|
||
@PublishedApi | ||
internal object AdminMailConfig : ReadOnlyPluginConfig("AdminMailConfig") { | ||
|
||
@ValueName("offline_notify") | ||
@ValueDescription("机器人下线时,发送邮件") | ||
val notify: Boolean by value(true) | ||
|
||
@ValueName("close_notify") | ||
@ValueDescription("机器人正常关闭时,也发送邮件") | ||
val close: Boolean by value(false) | ||
|
||
@ValueName("bot_offline") | ||
@ValueDescription("机器人下线时,接收邮件的地址") | ||
val offline: String by value("") | ||
|
||
@ValueName("log_backup") | ||
@ValueDescription("备份日志时,接收邮件的地址") | ||
val log: String by value("") | ||
|
||
var properties = Path("admin.mail.properties") | ||
private set | ||
|
||
@OptIn(ConsoleExperimentalApi::class) | ||
override fun onInit(owner: PluginDataHolder, storage: PluginDataStorage) { | ||
if (owner is JvmPlugin) { | ||
properties = owner.resolveConfigPath("admin.mail.properties") | ||
if (properties.notExists()) { | ||
properties.writeText( | ||
""" | ||
mail.host=smtp.example.com | ||
mail.auth=true | ||
mail.user=xxx | ||
mail.password=**** | ||
[email protected] | ||
mail.store.protocol=smtp | ||
mail.transport.protocol=smtp | ||
# smtp | ||
mail.smtp.starttls.enable=true | ||
mail.smtp.auth=true | ||
mail.smtp.timeout=15000 | ||
""".trimIndent() | ||
) | ||
owner.logger.info { "邮件配置文件已生成,请修改内容以生效 $properties" } | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
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 oc = Thread.currentThread().contextClassLoader | ||
try { | ||
block.invoke(props) | ||
} finally { | ||
Thread.currentThread().contextClassLoader = oc | ||
} | ||
|
||
if (props.getProperty("mail.smtp.localhost") == null) { | ||
props.setProperty("mail.smtp.localhost", props.getProperty("mail.host")) | ||
} | ||
|
||
val auth = object : 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) | ||
} | ||
} | ||
|
||
return try { | ||
Thread.currentThread().contextClassLoader = block::class.java.classLoader | ||
Session.getDefaultInstance(props, auth) | ||
} finally { | ||
Thread.currentThread().contextClassLoader = oc | ||
} | ||
} | ||
|
||
/** | ||
* 构建邮件 | ||
* @see MailContentBuilder | ||
*/ | ||
public fun buildMailContent(session: Session, block: MailContentBuilder.(MimeMessage) -> Unit): MimeMessage { | ||
val message = MimeMessage(session) | ||
val builder: MailContentBuilder | ||
|
||
val oc = Thread.currentThread().contextClassLoader | ||
try { | ||
Thread.currentThread().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 { | ||
Thread.currentThread().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() | ||
part.setText(StringBuilder().apply(builderAction).toString(), "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) | ||
} | ||
} |