英文:
Workaround for changing subject of EMail via IMAP java mail
问题
我知道IMAP和POP3有局限性,它们无法更改收到的电子邮件的主题(例如,您可以在Exchange ActiveSync中进行更改)。
我已经阅读了多个类似的案例,人们在其中提到一种解决方法,即在代码中创建电子邮件副本,对其进行操作,然后将其存储在文件夹中并删除原始电子邮件 - 例如在这里:
https://community.oracle.com/thread/1589468
在我的情况下,使用链接中示例中的方法不起作用,电子邮件主题保持不变。
如何通过Java邮件在IMAP/POP3中更改电子邮件主题?
英文:
I know that IMAP and POP3 are limited in that they can't change the subject of a received email (Which you can do in Exchange ActiveSync for example)
I have read multiple similar cases, where people mention a workaround by creating a copy of the email in code, manipulating it, then storing it in the folder and deleting the original - as for example here:
https://community.oracle.com/thread/1589468
In my case using the approach as in the examples in the link doesn't work and the email subject stays the same.
How can I change the email subject via java mail using IMAP/POP3?
答案1
得分: 1
经过许多的尝试和错误,我意识到通过调试电子邮件的标头,尽管主题行已经正确设置,但在Outlook电子邮件客户端中显示的并不是它,我还需要设置Thread-Topic
标头。此外,为了使邮件具有与之前相同的阅读状态,我还需要复制标志。
这是重命名单封电子邮件的完整可工作的Kotlin函数:
fun renameMessage(folder: Folder, message: Message, subject: String) {
try {
val renamedMessage = MimeMessage(message as MimeMessage)
renamedMessage.setSubject(subject)
renamedMessage.setHeader("Thread-Topic", subject)
renamedMessage.setFlags(message.flags ?: Flags(), true)
renamedMessage.saveChanges()
folder.appendMessages(arrayOf(renamedMessage))
} catch (e: Exception) {
println(e.message) //logger.error(e.message, e)
} catch (t: Throwable) {
println(t.message) //logger.error(t.message, t)
} finally {
//deleting original message
message.setFlag(Flags.Flag.DELETED, true)
folder.expunge()
}
}
以下是如何使用该函数的示例:
// for POP3
//String protocol = "pop3";
//String host = "outlook.office365.com";
//String port = "995";
// for IMAP
val protocol = "imap"
val host = "outlook.office365.com"
val port = "993"
//credentials
val userName = "example@outlook.com"
val password = "examplePassword"
val properties: Properties = getServerProperties(protocol, host, port)
val session = Session.getDefaultInstance(properties)
try {
// connects to the message store
val store = session.getStore(protocol)
store.connect(userName, password)
// opens the inbox folder
val folderInbox = store.getFolder("INBOX")
folderInbox.open(Folder.READ_WRITE)
// fetches new messages from server
val messages = folderInbox.messages
// process and tag email
for (message in messages){
//Your code to process each email here
renameMessage(folderInbox, message, "[PROCESSED] ${message.subject}")
}
// disconnect
folderInbox.close(false)
store.close()
} catch (e: NoSuchProviderException) {
println("No provider for protocol: $protocol") //logger.error(e.message, e)
} catch (e: MessagingException) {
println("Could not connect to the message store") //logger.error(e.message, e)
}
fun getServerProperties(protocol: String, host: String, port: String): Properties {
val properties = Properties()
// server setting
properties.put(String.format("mail.%s.host", protocol), host)
properties.put(String.format("mail.%s.port", protocol), port)
// SSL setting
properties.setProperty(String.format("mail.%s.socketFactory.class", protocol), "javax.net.ssl.SSLSocketFactory")
properties.setProperty(String.format("mail.%s.socketFactory.fallback", protocol), "false")
properties.setProperty(String.format("mail.%s.socketFactory.port", protocol), port)
return properties
}
该代码可以在重命名多封电子邮件时进行更好的优化,只需要调用一次folder.expunge()
。
英文:
After lots of trial and error I realized, through debugging the headers of the email, that even though the subject line was set properly, it was not what got displayed in the outlook email client and that I needed to set the header Thread-Topic
as well. Additionally for the message to have the same read state as before I also needed to copy the flags.
Here is the full working kotlin function for renaming a single email :
fun renameMessage(folder: Folder, message: Message, subject: String) {
try {
val renamedMessage = MimeMessage(message as MimeMessage)
renamedMessage.setSubject(subject)
renamedMessage.setHeader("Thread-Topic", subject)
renamedMessage.setFlags(message.flags ?: Flags(), true)
renamedMessage.saveChanges()
folder.appendMessages(arrayOf(renamedMessage))
} catch (e: Exception) {
println(e.message) //logger.error(e.message, e)
} catch (t: Throwable) {
println(t.message) //logger.error(t.message, t)
} finally {
//deleting original message
message.setFlag(Flags.Flag.DELETED, true)
folder.expunge()
}
}
Here is and example of how the function can be used:
// for POP3
//String protocol = "pop3";
//String host = "outlook.office365.com";
//String port = "995";
// for IMAP
val protocol = "imap"
val host = "outlook.office365.com"
val port = "993"
//credentials
val userName = "example@outlook.com"
val password = "examplePassword"
val properties: Properties = getServerProperties(protocol, host, port)
val session = Session.getDefaultInstance(properties)
try {
// connects to the message store
val store = session.getStore(protocol)
store.connect(userName, password)
// opens the inbox folder
val folderInbox = store.getFolder("INBOX")
folderInbox.open(Folder.READ_WRITE)
// fetches new messages from server
val messages = folderInbox.messages
// process and tag email
for (message in messages){
//Your code to process each email here
renameMessage(folderInbox, message, "[PROCESSED] ${message.subject}")
}
// disconnect
folderInbox.close(false)
store.close()
} catch (e: NoSuchProviderException) {
println("No provider for protocol: $protocol") //logger.error(e.message, e)
} catch (e: MessagingException) {
println("Could not connect to the message store") //logger.error(e.message, e)
}
fun getServerProperties(protocol: String, host: String, port: String): Properties {
val properties = Properties()
// server setting
properties.put(String.format("mail.%s.host", protocol), host)
properties.put(String.format("mail.%s.port", protocol), port)
// SSL setting
properties.setProperty(String.format("mail.%s.socketFactory.class", protocol), "javax.net.ssl.SSLSocketFactory")
properties.setProperty(String.format("mail.%s.socketFactory.fallback", protocol), "false")
properties.setProperty(String.format("mail.%s.socketFactory.port", protocol), port)
return properties
}
The code could be better optimized for renaming multiple emails, by calling folder.expunge()
only once.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论