更改通过IMAP Java邮件的主题的解决方法

huangapple go评论80阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2020年8月23日 23:22:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/63548711.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定