Skip to content

Commit

Permalink
Added simple API to read and write MIMEData objects
Browse files Browse the repository at this point in the history
Supports HTML, plaintext, embedded images and attachments
  • Loading branch information
klehmann committed Dec 3, 2020
1 parent 7657b55 commit 4e08b37
Show file tree
Hide file tree
Showing 70 changed files with 8,298 additions and 41 deletions.
9 changes: 9 additions & 0 deletions domino-jna-mime-jakartamail/NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Contains a copy of Apache Commons Email moved to the package "com.mindoo.domino.jna.mime.internal.jakarta"
to avoid classloader conflicts.
Apache Commons Email has also been tweaked to work with the new jakarta.mail instead of javax.mail.

https://commons.apache.org/proper/commons-email/

Copyright The Apache Software Foundation
Apache 2.0 license

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.mindoo.domino.jna.mime.internal;

import java.io.IOException;
import java.io.InputStream;

import com.mindoo.domino.jna.mime.attachments.IMimeAttachment;

import jakarta.mail.BodyPart;
import jakarta.mail.MessagingException;
import jakarta.mail.Part;

/**
* Implementation of {@link IMimeAttachment} that reads its
* data from a Jakarta {@link BodyPart}.
*
* @author Karsten Lehmann
*/
public class JakartaMailMimeBodyPartAttachment implements IMimeAttachment {
private Part m_bodyPart;

public JakartaMailMimeBodyPartAttachment(Part bodyPart) {
m_bodyPart = bodyPart;
}

@Override
public String getFileName() throws IOException {
try {
return m_bodyPart.getFileName();
} catch (MessagingException e) {
throw new IOException("Error accessing MIME body part", e);
}
}

@Override
public String getContentType() throws IOException {
try {
return m_bodyPart.getContentType();
} catch (MessagingException e) {
throw new IOException("Error accessing MIME body part", e);
}
}

@Override
public InputStream getInputStream() throws IOException {
try {
return m_bodyPart.getInputStream();
} catch (MessagingException e) {
throw new IOException("Error accessing MIME body part", e);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
package com.mindoo.domino.jna.mime.internal;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.EnumSet;

import com.mindoo.domino.jna.NotesDatabase;
import com.mindoo.domino.jna.NotesNote;
import com.mindoo.domino.jna.constants.MimeStreamItemizeOptions;
import com.mindoo.domino.jna.constants.MimeStreamOpenOptions;
import com.mindoo.domino.jna.errors.NotesError;
import com.mindoo.domino.jna.mime.IMimeDataAccessService;
import com.mindoo.domino.jna.mime.JakartaMailMIMEHelper;
import com.mindoo.domino.jna.mime.MIMEData;
import com.mindoo.domino.jna.mime.attachments.IMimeAttachment;
import com.mindoo.domino.jna.mime.internal.jakartamail.org.apache.commons.mail.EmailAttachment;
import com.mindoo.domino.jna.mime.internal.jakartamail.org.apache.commons.mail.EmailException;
import com.mindoo.domino.jna.mime.internal.jakartamail.org.apache.commons.mail.HtmlEmail;
import com.mindoo.domino.jna.utils.StringUtil;

import jakarta.activation.DataSource;
import jakarta.activation.MimetypesFileTypeMap;
import jakarta.mail.BodyPart;
import jakarta.mail.MessagingException;
import jakarta.mail.Multipart;
import jakarta.mail.Part;
import jakarta.mail.internet.MimeMessage;

/**
* Implementation of {@link IMimeDataAccessService} that uses the Jakarta Mail
* API to read and write MIME data.
*
* @author Karsten Lehmann
*/
public class JakartaMailMimeDataAccessService implements IMimeDataAccessService {
private static final MimetypesFileTypeMap mimeTypes = new MimetypesFileTypeMap();

@Override
public MIMEData getMimeData(NotesNote note, String itemName) {
try {
MimeMessage mimeMessage = JakartaMailMIMEHelper.readMIMEMessage(note, itemName, EnumSet.of(MimeStreamOpenOptions.MIME_INCLUDE_HEADERS));

MIMEData mimeData = new MIMEData();
populateMIMEData(mimeMessage, mimeData);

return mimeData;
} catch (IOException e) {
NotesDatabase db = note.getParent();
throw new NotesError(0, "Error reading MIMEData from item "+itemName+" of document with UNID "+
note.getUNID()+" in database "+db.getServer()+"!!"+db.getRelativeFilePath(), e);
} catch (MessagingException e) {
NotesDatabase db = note.getParent();
throw new NotesError(0, "Error reading MIMEData from item "+itemName+" of document with UNID "+
note.getUNID()+" in database "+db.getServer()+"!!"+db.getRelativeFilePath(), e);
} catch (NotesError e) {
if (e.getId() == 546) {
//Note item not found
return null;
}
else {
throw e;
}
}
}

@Override
public void setMimeData(NotesNote note, String itemName, MIMEData mimeData) {
String html = mimeData.getHtml();
String text = mimeData.getPlainText();

try {
HtmlEmail mail = new HtmlEmail();

//add some required fields required by Apache Commons Email (will not be written to the doc)
mail.setFrom("mr.sender@acme.com", "Mr. Sender");
mail.addTo("mr.receiver@acme.com", "Mr. Receiver");
mail.setHostName("acme.com");

mail.setCharset("UTF-8");

//add embeds
for (String currCID : mimeData.getContentIds()) {
IMimeAttachment currAtt = mimeData.getEmbed(currCID);

MimeAttachmentDataSource dataSource = new MimeAttachmentDataSource(currAtt);
mail.embed(dataSource, currAtt.getFileName(), currCID);
}

//add attachments
for (IMimeAttachment currAtt : mimeData.getAttachments()) {
MimeAttachmentDataSource dataSource = new MimeAttachmentDataSource(currAtt);

mail.attach(dataSource, currAtt.getFileName(), null, EmailAttachment.ATTACHMENT);
}

if (!StringUtil.isEmpty(text)) {
mail.setTextMsg(text);
}
mail.setHtmlMsg(html);

mail.buildMimeMessage();
MimeMessage mimeMsg = mail.getMimeMessage();

while (note.hasItem(itemName)) {
note.removeItem(itemName);
}

JakartaMailMIMEHelper.writeMIMEMessage(note, itemName, mimeMsg, EnumSet.of(MimeStreamItemizeOptions.ITEMIZE_BODY));

} catch (EmailException | IOException | MessagingException e) {
NotesDatabase db = note.getParent();
throw new NotesError(0, "Error writing MIME content to item "+itemName+" of document with UNID "+
note.getUNID()+" of database "+db.getServer()+"!!"+db.getRelativeFilePath(), e);
}
}

/**
* Recursively traverse the MIME structure reading HTML/plaintext
* content and information about inlines/attachments
*
* @param content return value of {@link MimeMessage#getContent()}
* @param retMimeData {@link MIMEData} to populate with html/plaintext/inlines/attachments
* @throws MessagingException for errors parsing the MIME data
* @throws IOException for general I/O errors
*/
private void populateMIMEData(Object content, MIMEData retMimeData) throws MessagingException, IOException {
if (content==null) {
return;
}

if (content instanceof Multipart) {
Multipart multipart = (Multipart) content;

for (int i=0; i<multipart.getCount(); i++) {
BodyPart currBodyPart = multipart.getBodyPart(i);

populateMIMEData(currBodyPart, retMimeData);
}
}
else if (content instanceof Part) {
Part part = (Part) content;

String disposition = part.getDisposition();

if (part.isMimeType("text/html")
&& (StringUtil.isEmpty(disposition) || "inline".equals(disposition))) {
Object htmlContent = part.getContent();
if (htmlContent instanceof String) {
retMimeData.setHtml((String) htmlContent);
}
return;
}
else if (part.isMimeType("text/plain")
&& (StringUtil.isEmpty(disposition) || "inline".equals(disposition))) {
Object textContent = part.getContent();
if (textContent instanceof String) {
retMimeData.setPlainText((String) textContent);
}
return;
}

if (!part.isMimeType("multipart/related") &&
!part.isMimeType("multipart/mixed") &&
!part.isMimeType("multipart/alternative")) {
//either inline file or attachment
JakartaMailMimeBodyPartAttachment mimeAtt = new JakartaMailMimeBodyPartAttachment(part);

String[] currContentIdArr = part.getHeader("Content-ID");
String currContentId = currContentIdArr!=null && currContentIdArr.length>0 ? currContentIdArr[0] : null;

if (StringUtil.isEmpty(currContentId)) {
retMimeData.attach(mimeAtt);
}
else {
if (currContentId.startsWith("<")) {
currContentId = currContentId.substring(1);
}
if (currContentId.endsWith(">")) {
currContentId = currContentId.substring(0, currContentId.length()-1);
}

retMimeData.embed(currContentId, mimeAtt);
}
}
else {
Object bodyContent = part.getContent();
if (bodyContent!=null) {
populateMIMEData(bodyContent, retMimeData);
}
}
}
else if (content instanceof InputStream) {
((InputStream)content).close();
}
}

/**
* Implementation of {@link DataSource} that reads its data from
* a {@link IMimeAttachment}.
*
* @author Karsten Lehmann
*/
private static class MimeAttachmentDataSource implements DataSource {
private IMimeAttachment m_att;

public MimeAttachmentDataSource(IMimeAttachment att) {
m_att = att;
}

@Override
public InputStream getInputStream() throws IOException {
return m_att.getInputStream();
}

@Override
public OutputStream getOutputStream() throws IOException {
throw new IOException("cannot do this");
}

@Override
public String getContentType() {
try {
String contentType = m_att.getContentType();

if (StringUtil.isEmpty(contentType)) {
String fileName = getName();
if (!StringUtil.isEmpty(fileName)) {
contentType = mimeTypes.getContentType(fileName);
}
}

if (StringUtil.isEmpty(contentType)) {
contentType = "application/octet-stream";
}

return contentType;

} catch (IOException e) {
throw new NotesError(0, "Error reading content type from MIME attachment", e);
}
}

@Override
public String getName() {
try {
return m_att.getFileName();
} catch (IOException e) {
throw new NotesError(0, "Error reading content type from MIME attachment", e);
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* under the License.
* ==========================================================================
*/
package org.apache.commons.mail;
package com.mindoo.domino.jna.mime.internal.jakartamail.org.apache.commons.mail;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* under the License.
* ==========================================================================
*/
package org.apache.commons.mail;
package com.mindoo.domino.jna.mime.internal.jakartamail.org.apache.commons.mail;

import jakarta.activation.DataSource;
import java.io.IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* under the License.
* ==========================================================================
*/
package org.apache.commons.mail;
package com.mindoo.domino.jna.mime.internal.jakartamail.org.apache.commons.mail;

import jakarta.mail.Authenticator;
import jakarta.mail.PasswordAuthentication;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* under the License.
* ==========================================================================
*/
package org.apache.commons.mail;
package com.mindoo.domino.jna.mime.internal.jakartamail.org.apache.commons.mail;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
Expand All @@ -26,6 +26,12 @@
import java.util.Map;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.mindoo.domino.jna.mime.internal.jakartamail.org.apache.commons.mail.util.IDNEmailAddressConverter;

import jakarta.mail.Authenticator;
import jakarta.mail.Message;
import jakarta.mail.MessagingException;
Expand All @@ -37,11 +43,6 @@
import jakarta.mail.internet.MimeMessage;
import jakarta.mail.internet.MimeMultipart;
import jakarta.mail.internet.MimeUtility;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.apache.commons.mail.util.IDNEmailAddressConverter;

/**
* The base class for all email messages. This class sets the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* under the License.
* ==========================================================================
*/
package org.apache.commons.mail;
package com.mindoo.domino.jna.mime.internal.jakartamail.org.apache.commons.mail;

import java.net.URL;

Expand Down
Loading

0 comments on commit 4e08b37

Please sign in to comment.