Mail Module
Last modified by Vincent Massol on 2024/02/26 17:52
Description
The goal is introduce a Mail API in the XWiki Platform to provide mail-related APIs.
History & Status
- Ludovic sent an email to propose a modification of the mailsender plugin: http://markmail.org/message/pfoyi4qeqvlc75yo
- Discussions ensued and Thomas Delafosse started working on a new xwiki-platform-mail module (component-based) to replace the old mailsender plugin
- Thomas Delafosse put a first version of his ideas in his GitHub repo at: https://github.com/tdelafosse/mailSender
- Then Thomas Delafosse moved his code to https://github.com/xwiki-contrib/xwiki-platform-mail/
- Work was stopped by Thomas Delafosse
- Now waiting for someone to take over...
Use Cases
- UC1: Be able to send multipart emails with any type of mime type content (html, text, vcalendar, etc)
- UC2: Be able to get the mail content to send by rendering the content of an XWiki document (a.k.a a template)
- UC3: Ensure the API is easy to use from Velocity (script service)
- UC4: SMTP config should be able to be either specified explicitly or taken from XWiki configuration
- UC5: Ability to easily embed images in the email (i.e. generate cid)
- UC6: Ability to easily send an XWiki page by email (i.e. automatically embed images from that page in the email)
- UC7: Allow both reading (POP3, IMAP) and sending (SMTP) emails, supporting SSL
- UC8: Ability to send batch of emails
API Proposal
Scripting API
// Message creation, internally creates a JavaMail MimeMessage
$message = $services.mailSender.createMessage()
$message = $services.mailSender.createMessage(from, to, subject)
$message = $services.mailSender.createMessage(from, to, cc, bcc, subject)
// Set from, to, cc, bcc, subject
// Note that "from" is optional and if not specified, taken from Mail configuration
$message.setFrom("[email protected](mailto:[email protected])")
$message.addToRecipient("[email protected](mailto:[email protected])”)
$message.addToRecipients(["[email protected](mailto:[email protected])”, ...])
$message.addCcRecipient("[email protected](mailto:[email protected])”)
$message.addCcRecipients(["[email protected](mailto:[email protected])”, ...])
$message.addBccRecipient("[email protected](mailto:[email protected])”)
$message.addBccRecipients(["[email protected](mailto:[email protected])”, ...])
// Optional:
// Need a Converter implementation to convert from String to javax.mail.Message.RecipientType
$message.addRecipient("[email protected](mailto:[email protected])”, "to|bcc|cc")
$message.addRecipients("[email protected](mailto:[email protected])”, "to|bcc|cc")
$message.setSubject('Lorem Ipsum')
// Add the Content
// Note: the first parameter is a component hint. If no implementation corresponds to it, a default implementation is used which converts it to a Mime Type
// Note: We create by default a MultiPart("mixed") and the addPart() calls generate MultiPartBody added to this multipart.
// Add simple text to message
$message.addPart("text", "text message")
// Add simple text to message with a header
$message.addPart("text", "text message", {"headers" : { "Content-Transfer-Encoding" : "quoted-printable"}})
// Add simple HTML to message
$message.addPart("html", "html message")
// Add HTML + alternate text to message
$message.addPart("html", "html message", {"alternate" : "text message"})
// Add HTML + alternate text + embedded images + attachments to message
// Note: $attachments is of type List<Attachment>
$message.addPart("html", "html message", {"alternate" : "text message", "attachments" : $attachments})
// Add an XWiki attachment to message
$message.addPart("attachment", Attachment)
// And XWiki attachment to message from an Attachment reference
$message.addPart("attachment", AttachmentReference)
// Add all attachments found in the passed document reference to the message
$message.addPart("attachment", DocumentReference)
// Add all attachments to message
$message.addPart("attachments", List<Attachment>)
// Add a wiki page to message with embedded images and attachments
$message.addPart("document", DocumentReference)
// Generate the message from a template containing a XWiki.Mail object
$message.addPart("template", DocumentReference, {"velocityVariables" : { "var1" : "value1" }})
// Send Message now, asynchronously
$message.send()
// Send Message at some date
$message.send(Date)
// Wait for the message to be sent
$message.waitTillSent()
// Internally messages are added to a queue when send() is called and sent asynchronously by batches of N messages at a time. The number of messages to send in a batch is controlled by the Mail configuration in the Admin. We can imagine an API to get the mail configuration and override it temporarily:
$mailConfiguration = $services.mailSender.getConfiguration()
$mailConfiguration.setFrom(...)
$mailConfiguration.setSmtpAddress(...)
$mailConfiguration.setBatchSize(...)
// And then:
$message.send(MailConfiguration)
$message.send(Date, MailConfiguration)
$message = $services.mailSender.createMessage()
$message = $services.mailSender.createMessage(from, to, subject)
$message = $services.mailSender.createMessage(from, to, cc, bcc, subject)
// Set from, to, cc, bcc, subject
// Note that "from" is optional and if not specified, taken from Mail configuration
$message.setFrom("[email protected](mailto:[email protected])")
$message.addToRecipient("[email protected](mailto:[email protected])”)
$message.addToRecipients(["[email protected](mailto:[email protected])”, ...])
$message.addCcRecipient("[email protected](mailto:[email protected])”)
$message.addCcRecipients(["[email protected](mailto:[email protected])”, ...])
$message.addBccRecipient("[email protected](mailto:[email protected])”)
$message.addBccRecipients(["[email protected](mailto:[email protected])”, ...])
// Optional:
// Need a Converter implementation to convert from String to javax.mail.Message.RecipientType
$message.addRecipient("[email protected](mailto:[email protected])”, "to|bcc|cc")
$message.addRecipients("[email protected](mailto:[email protected])”, "to|bcc|cc")
$message.setSubject('Lorem Ipsum')
// Add the Content
// Note: the first parameter is a component hint. If no implementation corresponds to it, a default implementation is used which converts it to a Mime Type
// Note: We create by default a MultiPart("mixed") and the addPart() calls generate MultiPartBody added to this multipart.
// Add simple text to message
$message.addPart("text", "text message")
// Add simple text to message with a header
$message.addPart("text", "text message", {"headers" : { "Content-Transfer-Encoding" : "quoted-printable"}})
// Add simple HTML to message
$message.addPart("html", "html message")
// Add HTML + alternate text to message
$message.addPart("html", "html message", {"alternate" : "text message"})
// Add HTML + alternate text + embedded images + attachments to message
// Note: $attachments is of type List<Attachment>
$message.addPart("html", "html message", {"alternate" : "text message", "attachments" : $attachments})
// Add an XWiki attachment to message
$message.addPart("attachment", Attachment)
// And XWiki attachment to message from an Attachment reference
$message.addPart("attachment", AttachmentReference)
// Add all attachments found in the passed document reference to the message
$message.addPart("attachment", DocumentReference)
// Add all attachments to message
$message.addPart("attachments", List<Attachment>)
// Add a wiki page to message with embedded images and attachments
$message.addPart("document", DocumentReference)
// Generate the message from a template containing a XWiki.Mail object
$message.addPart("template", DocumentReference, {"velocityVariables" : { "var1" : "value1" }})
// Send Message now, asynchronously
$message.send()
// Send Message at some date
$message.send(Date)
// Wait for the message to be sent
$message.waitTillSent()
// Internally messages are added to a queue when send() is called and sent asynchronously by batches of N messages at a time. The number of messages to send in a batch is controlled by the Mail configuration in the Admin. We can imagine an API to get the mail configuration and override it temporarily:
$mailConfiguration = $services.mailSender.getConfiguration()
$mailConfiguration.setFrom(...)
$mailConfiguration.setSmtpAddress(...)
$mailConfiguration.setBatchSize(...)
// And then:
$message.send(MailConfiguration)
$message.send(Date, MailConfiguration)
Java API
- MailConfiguration component role with implementation taking the configuration values from the Administration
- MimeBodyPart MimeBodyPartFactory.create(T source)
- MimeMessageFactory to make it simple to create MimeMessage
- MailSender component role to make the glue between all + ability to send mails asynchronously and by batch
Spirit: It should be possible to send mail using directly the JavaMail API and using the helper components defined above or use the MailSender component which acts as a helper but is not as generic.
@Inject MailSenderConfiguration configuration;
@Inject @Named("html") MimeBodyPartFactory htmlPartFactory;
@Inject MimeMessageFactory messageFactory;
@Inject MailSender mailSender;
// Step 1: Create a JavaMail Session
//... with authentication:
Session session = Session.getInstance(configuration.getAllProperties(), new XWikiAuthenticator(configuration));
//... without authentication:
Session session = Session.getInstance(configuration.getAllProperties());
// Step 2: Create the Message to send
MimeMessage message = new MimeMessage(session);
message.setSubject("subject");
message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress("[email protected]"));
// Step 3: Add the Message Body
Multipart multipart = new MimeMultipart("mixed");
// Add HTML in the body, with a text alternative and attachments
Map<String, Object> parameters = new HashMap<>();
parameters.put("alternative", "text");
parameters.put("attachments", attachments);
multipart.addBodyPart(htmlPartFactory.create("some html here", parameters));
message.setContent(multipart);
// Step 4: Send the mail
sender.send(message, session);
@Inject @Named("html") MimeBodyPartFactory htmlPartFactory;
@Inject MimeMessageFactory messageFactory;
@Inject MailSender mailSender;
// Step 1: Create a JavaMail Session
//... with authentication:
Session session = Session.getInstance(configuration.getAllProperties(), new XWikiAuthenticator(configuration));
//... without authentication:
Session session = Session.getInstance(configuration.getAllProperties());
// Step 2: Create the Message to send
MimeMessage message = new MimeMessage(session);
message.setSubject("subject");
message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress("[email protected]"));
// Step 3: Add the Message Body
Multipart multipart = new MimeMultipart("mixed");
// Add HTML in the body, with a text alternative and attachments
Map<String, Object> parameters = new HashMap<>();
parameters.put("alternative", "text");
parameters.put("attachments", attachments);
multipart.addBodyPart(htmlPartFactory.create("some html here", parameters));
message.setContent(multipart);
// Step 4: Send the mail
sender.send(message, session);
Configuration Parameters
- Introduce new parameters in xwiki.properties:mail.sender.host = ...
mail.sender.port = ...
mail.sender.username = ...
mail.sender.password = ...
mail.sender.from = ...
mail.sender.properties = ... = ...
mail.sender.properties = ... = ... - Algorithm: first try to find existing parameter names (smtp_server, smtp_port, smtp_from, smtp_server_username, smtp_server_password, javamail_extra_props) in a user, space and wiki level ConfigurationSource and if not found then look for the mail.sender.* property names from a xwikiproperties ConfigurationSource.
Implementation Ideas
- Current Mailsender plugin: https://github.com/xwiki/xwiki-platform/tree/master/xwiki-platform-core/xwiki-platform-mailsender
- Current Mail plugin: https://github.com/xwiki/xwiki-platform/tree/master/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/plugin/mail
- Existing MailArchive Application (read mails): http://extensions.xwiki.org/xwiki/bin/view/Extension/MailArchive+Application
- Existing APIs to consider:
- Could have several modules:
- xwiki-commons-mail-common: Store classes common to the other modules
- xwiki-commons-mail-send: Ability to send emails
- xwiki-commons-mail-read: Ability to read emails
- xwiki-platform-mail: Wiki specific features, like getting the template from a wiki page and rendering it