| Name | Form Mail NG |
|---|---|
| Vendor | Adaptavist.com Ltd (Website) |
| Authors | Dan Hardiker |
| Homepage | http://confluence.atlassian.com/display/CODEGEIST/Form+Mail+NG |
| Issue Management | http://jira.adaptavist.com/browse/FMNG |
| Categories | Communication Macros |
| Version | 1.2.1 |
| Availability | Confluence v2.8-m7-r2 to v2.10-m1 |
| State | Stable |
| Support |
|
| License | Freeware / Open Source (BSD) |
| Price | Donate |
| Release Docs | http://confluence.atlassian.com/display/CODEGEIST/Form+Mail+NG |
| Java API Docs | n/a |
| Download Source | http://svn.atlassian.com/svn/public/contrib/confluence/form-mail-ng/tags/1.2.1/ |
| Download JAR | form-mail-ng-1.2.1.jar |
Contents
Description/Features
A completely re-engineered version of the Form Mail Plugin. Hold no preconceptions; this is one small step for plugins, one giant leap for Confluence mailing.
For a quite sometime now I've wanted to overhaul the existing Form Mail plugin as it wasn't flexible enough and, in some cases, simply didn't work. So what better time to write another than when you're wife is in very slow labor (kid ain't out yet and is already demanding) and you can't get on with any real work.
So here is the feature hit list:
- Admin console
There is now an Administration console action where you can define multiple sets of configuration settings. This has the advantage of the end user having no way to gain your email address or even your username. You can also keep your public key out of sight if you like, and the success HTML that is shown – CODEGEIST:more details ...
- Improved Security
In addition to the implicit security issues that the Admin console above adds, the complete overhaul of the code base has resolved a few potential exploitable flaws (although the cases where they could be exploited are admit idly rare).
- Flexible Configuration
You can either define the configuration in the new Admin console action, or you can specify all the settings in the macros in the markup, or you can base your settings off a configuration and override certain fields in the markup; it's up to you!
- Macro-Orientated Design
You now define a wrapping form, and lay out the form elements intermingled with standard wiki notation in a manner familiar to those who use the Scaffolding Plugin or the Advanced Search Plugin. This allows you to be far more creative in how you layout your fields, and gives you much more control of their configuration – CODEGEIST:more details ...
- Special Field Names
With the new dynamically defined layout, comes a new way of passing through data for the special fields, such as from email address and subject. These all have defaults and none are required to be entered. All you have to do is name your field as "from", "from-name" or "subject" and it will get through. Special fields do not make it into the body, and in the case of multiple fields with the same special name, the last one wins out.
- Validation
You can now specify a validator for each field as well as required flag to make sure that the field contains at least something – CODEGEIST:more details ...
- Velocity Values
On most of the macros which take a value, you can now render it using Velocity in the vtlValue parameter (or using the render=velocity param on the {mail-textarea} macro). This allows you access to the standard context that Confluence provides, as well as adding a some extra variables, so that you can display sensible defaults for things like the user email address or pass the user's name as a hidden field – CODEGEIST:more details ...
- PGP Encrypted Emails
Ever wanted to take credit card information or other sensitive details on your Confluence site, and have them securely transmitted back to their destination? Now you can, using OpenPGP's PKI infrastucture – CODEGEIST:more details ...
- Data Handlers
Ever wanted to take the form data, and put it in a pseudo database instead of having it emailed to you? Now you can, using the Bandana Collector (it even supports data types for future expansion!) – CODEGEIST:more details ...
- Multiple Forms
The original Form Mail plugin could only be used once on a page due to it's design, this limitation is no longer applicable as Form Mail NG has been written extensible from the ground up. It is no longer considered a throw away, quick-fire code base.
Developer Rippable Features
All developers rip other developers code as a quick way to learn new APIs and improve their own code. Here are some of the implementations you might find useful that I believe are unique to this plugin (to the best of my knowledge):
- Usage of ExtJS for the dialogs in the Admin console action.
- Serialisation of Java Object to JSON using XStream.
The Admin console action uses a "direct load, AJAX command" system, which loads the Java Objects directly from the action's HTML output as it's injected as JSON. The table is dynamically created, and changes (add/update/delete) are then serialized back using DWR.
There is also an example of using Confluence's cluster-safe cacheManager to store TempFormMail objects (hardly rocket science, but hey – I didn't know it was cluster-safe!).
Developer Instructions
Build
You will need Maven 2 installed:
- Subversion checkout http://svn.atlassian.com/svn/public/contrib/confluence/form-mail-ng/trunk/
- Enter the "lib" directory
- Run install.bat / install.sh to add the libraries to your local repository
- Run mvn package to create your Confluence plugin in the "target" directory
Edit
If you run mvn idea:idea instead you'll get an IDEA project you can use to edit with.
Screenshots
Usage
See the Examples if you want a quick start in to getting something up and running. This section serves as the macro usage documentation.
{mail-form}
This is the encompassing form within which all the other macros must be placed. The other macros will have undocumented behaviour in cases where they are placed outside of a {mail-form} macro. The form can either be linked to a configuration by id, have it's settings provided in parameters and encapsulated macros, or indeed both where the settings override that of the configuration.
| Parameter | Description | Type | Default | Required |
|---|---|---|---|---|
| id | The Form Mail configuration ID | string | none | |
| collector | The collector to use | string (email / bandana) | |
|
| destination | The destination to use, either the email address or bandana store, depending on collector used | string | none | |
{mail-input}
This provides an input field synonymous to a HTML input field and has no body.
| Parameter | Description | Value | Default | Required |
|---|---|---|---|---|
| name | Name of Field (also used as HTML node name) | string | none | |
| id | HTML ID of Field (unused by FormMailNG) | string | none | |
| cssClass | HTML CSS Class value | string | none | |
| cssStyle | HTML CSS Style value | string | none | |
| dataType | reserved for future use | string (String/int/long/boolean/Boolean/Date) | String | |
| validation | Validation mode, see Validation | string | none | |
| required | Is this field require a value? | boolean | false | |
| disabled | Is this field disabled from user interaction? | boolean | false | |
| type | Type of Field | string (text / checkbox / radio / hidden) | none | |
| value | Initial value of the Field | string | none | |
| vtlValue | Velocity value (overrides the above), see Available Velocity Context | velocity template string | none | |
| checked | Inital State (only valid for type=checkbox/radio) | boolean | false | |
{mail-label}
This provides a label element synonymous to a HTML label element, its body is wiki rendered and is used as the label element's contents.
| Parameter | Description | Value | Default | Required |
|---|---|---|---|---|
| for | Field ID this label is for | string | empty | |
{mail-select}
This provides an select field (drop-down list) synonymous to a HTML select field, with options defined in it's body by the {mail-option} macro.
| Parameter | Description | Value | Default | Required |
|---|---|---|---|---|
| name | Name of Field (also used as HTML node name) | string | none | |
| id | HTML ID of Field (unused by FormMailNG) | string | none | |
| cssClass | HTML CSS Class value | string | none | |
| cssStyle | HTML CSS Style value | string | none | |
| dataType | reserved for future use | string (String/int/long/boolean/Boolean/Date) | String | |
| validation | Validation mode, see Validation | string | none | |
| required | Is this field require a value? | boolean | false | |
| disabled | Is this field disabled from user interaction? | boolean | false | |
| nullLabel | The label for the empty option at the head of the select list | string | none | |
{mail-option}
This provides an option field synonymous to a HTML option field, its body is wiki rendered and is the outputted label for the option.
| Parameter | Description | Value | Default | Required |
|---|---|---|---|---|
| value | Value of the Field | string | empty | |
| selected | Is this Option Selected | boolean | false | |
{mail-textarea}
This provides an textarea field synonymous to a HTML textarea field, with the unrendered body being it's value.
| Parameter | Description | Value | Default | Required |
|---|---|---|---|---|
| name | Name of Field (also used as HTML node name) | string | none | |
| id | HTML ID of Field (unused by FormMailNG) | string | none | |
| cssClass | HTML CSS Class value | string | none | |
| cssStyle | HTML CSS Style value | string | none | |
| dataType | reserved for future use | string (String/int/long/boolean/Boolean/Date) | String | |
| validation | Validation mode, see Validation | string | none | |
| required | Is this field require a value? | boolean | false | |
| disabled | Is this field disabled from user interaction? | boolean | false | |
{mail-submit}
This provides an submit button synonymous to a HTML submit button. While there is no requirement for a button to exist, there wouldn't be any other way for the user to submit the form.
| Parameter | Description | Value | Default | Required |
|---|---|---|---|---|
| default | Label for the Button | string | Submit | |
{mail-success}
This macro sets or overrides what is on successful submission. The body is rendered according to the render parameter, if there is no renderer specified then it is outputted as raw HTML.
| Parameter | Description | Value | Default | Required |
|---|---|---|---|---|
| render | method to use for rendering | string (wiki/velocity) | none | |
Examples
Here are 3 examples, which should get you whet your appetites for what is possible. Now that you can fit it into any design it is really only limited by your imagination.
The simplest valid usage would be:
{mail-form:destination=email@example.com} {mail-submit} {mail-form}
This is rather useless and I doubt there is any practical use for this. Technically you don't even need the submit macro, although without that the form would be utterly useless. Have a look through some of the example for starting points for a real world use of this plugin.
Basic Example

This is about as basic as it comes, it's just a message box with a submit button! The subject and the from details will be left to Confluence to decide.
h2. Send us a Message
{mail-form:destination=email@example.com}
*Message*
{mail-textarea:name=message|cssStyle=width: 500px; height: 100px}{mail-textarea}
{mail-submit}
{mail-form}
Once sent the default success HTML will be spat out, which is really just a thank you message.
Call Back Example
"OK – this looks a bit more practical."

You want to offer the user a form where they can ask your sales team for a callback. This time you don't want to show the email address in the wiki markup (as it's visible by anyone who can view the rendered page after all). Instead you want to use the email address of a confluence username, specifically salesUsername.
You also want to set the subject, ensure you get a phone number and default their name to the logged in user's full name (anonymous users should see the field empty). The form should contain a select box with 5 options ranging from "now" to "1 hour", with the latter being the default.
The submit button's text should read "Call me!", and on success it should display a "Callback Accepted" Confluence {tip} message box telling them that their request has been accepted and to expect the call.
{mail-form:destination=~salesUsername}
{mail-input:type=hidden|name=subject|value=Call Request}
{info:title=Call Request}
Your Phone Number
{mail-input:type=text|name=phoneNum|cssStyle=width: 200px|required=true}
Your Name
{mail-input:type=text|name=fullName|cssStyle=width: 200px|vtlValue=$!user.fullName}
Time
{mail-select:name=eta}
{mail-option:value=0|selected=true}Now!{mail-option}
{mail-option:value=5|selected=true}5 minutes{mail-option}
{mail-option:value=15|selected=true}5 minutes{mail-option}
{mail-option:value=30|selected=true}30 minutes{mail-option}
{mail-option:value=60|selected=true}1 hour{mail-option}
{mail-select}
{mail-submit:Call me!}
{info}
{mail-success:render=wiki}
{tip:title=Callback Accepted}Thank you for requesting a callback, please expect our call.{tip}
{mail-success}
{mail-form}
... and the plugin isn't breaking a sweat!
Credit Card Example
"Jeez! You're not suggesting I get customers to email me their credit card details?"
Why not? This plugin supports OpenPGP cryptography (CODEGEIST:as described here), and for this we'll be setting things up a little different. This time, we'll be setting up a FormMail configuration.
Note: You will need Confluence and your mail reader to be set up for PGP encryption, see the above link for more details.
Step 1: Create the Configuration
- Go through to the Administration console
- Select Form Mails
- Select Create Form Mail
- Set ID: orders
- Set Encryption Public Key: your public key
- Set Email: your email address
- Save by clicking OK
-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.7 (MingW32) VB4KDqdTck8Wq9SgwgDroqI+OMXRH8K0Cts2++OK7YL9Jp4U5LQnRGFuIEhhcmRp mQGiBEYl1+URBACV3EkbOtkyhYEj9O1j2Uk08D/0KW1aWE/Qp48qmSu/GLq1rm8a ct4pKxiAsQX3tzKYTBFn67osBuIPutmHKMfzoof/hsR4f+TFjyJSOrRi9T4x4+AK RiXX5QIbDAUJA8JnAAAKCRDe5SG+6dd2ZjjCAJ9BBY47A0P8sk521ZUaE0JKrHlK 4DzMNr9Di9wCRxfUwJ4QWYEpJumsjl6ODMTrVXIIsBuIPu5yYj+HF0skp+BiNoCK sBuIPu5yYj+HF0skpSaRykrdzkAiPtdXnnw+bF+QmWtwbCP4QfNhyIXEfzAm+Rwr wxJmMsCY68cMEUCgd7/bZSvCKz9evRApjpsIavC5IZGjoCcABhTJeHX4jUa2qSAW VB4KDqdTck8Wq9SgwgDroqI+OMXRH8K0Cts2++OK7YL9Jp4U5LQnRGFuIEhhcmRp a2VyIDxkaGFyZGlrZXJAYWRhcHRhdmlzdC5jb20+iGYEExECACYFAkYl1+UCGwMF 9r8pamwaL8vvq1OFArbckF/6+acZF8yGEyIal8tB20oKDv2rGpblJnD2azPPoyEW kwM3XrM7LvY2bryDuAt+3hmF5JHxQc5HmGCvVpCK2WoH1mj/bd52fDUu7u8Z8jRj CQPCZwAGCwBx8B++dnXiZdf0iziZmMPuyb89fSWqGWFO+BiNoCKbDAUJA8JnAAAB 9r8pamwaL8vvq1OFArbckF/6+acZF8yGEyIal8tB20oKDv2rGpblJnD2azPPoyEW sIavC5IZGjoCcABhTJeHX4jUa2qSAWwxJmMsCY68cMEUCgd7/bZSvCKz9evRApjp tvbVGd+7JMg2xh7CGG6aZ1Br3UAn/cFchfkhh51F/yyCgP0DbR6ITwQYEQIADwUC agCcCRTioz3r59J5faQlTLE/MwBZgbU= =IlyQ -----END PGP PUBLIC KEY BLOCK-----
Step 2: Add the Wiki Notation
- Link the {mail-form} to the orders configuration by id.
- Add a hidden subject field, which will include the user's full name if logged in.
- Add a hidden confUser field containing the username if logged in.
- Add a hidden URL field containing the URL including query string if present.
- Add a required product select field, which has 2 options, and neither is selected initially with a message instead reading "--- Select a Product --".
- Add a required contactName text field, defaulting to the user's full name if logged in.
- Add a required contactEmail text field, defaulting to the user's email address if logged in, and is validated to be an email address.
- Add a required contactAddress text area.
- Add a required creditCard text field validated to be entirely numeric.
- All fields should appear in a standard confluence table, with CSS width settings set appropriately.
{mail-form:id=orders}
{mail-input:type=hidden|name=subject|vtlValue=Order#if($user) for $!user.fullName#end}
{mail-input:type=hidden|name=confUser|vtlValue=$!user.name}
{mail-input:type=hidden|name=URL|vtlValue=$req.requestURL#if($req.queryString)?$req.queryString#end}
|| Product | {mail-select:name=product|nullValue=--- Select a Product ---|required=true}
{mail-option:value=prodA}Option A{mail-option}
{mail-option:value=prodB}Option B{mail-option}
{mail-select} |
|| Contact Name | {mail-input:type=text|name=contactName|cssStyle=width: 170px|vtlValue=$!user.fullName|required=true} |
|| Contact Email | {mail-input:type=text|name=contactEmail|cssStyle=width: 100%|validation=email|vtlValue=$!user.email|required=true} |
|| Contact Address | {mail-textarea:name=contactAddress|cssStyle=width: 300px; height: 120px|required=true}{mail-textarea} |
|| Credit Card Number | {mail-input:type=text|name=creditCard|cssStyle=width: 100%|validation=num|required=true} |
{mail-submit:Purchase}
{mail-success:render=wiki}
{tip:title=Order Accepted}Thank you -- we will be in touch once we have processed your order.{tip}
{mail-success}
{mail-form}
Step 3: Sit back and Wait
Neat huh!
Documentation
If you are looking for more in depth documentation about the concepts and APIs that power this plugin, then here is the documentation which should set you off in the right direction.
Validation
| JavaScript Only The validation is all performed client side as if someone wants to hack their way around the interface and hook onto the API to circumvent validation they will. It's just not worth it, so if you have any automatic processing picking up the form data, then you will need to make sure you implement your own validation. You should be doing that anyway as you can never trust the input ... right? |
Most of the macros support validation, the most basic of which is the required=true parameter. This isn't technically a validator, it's just a flag to tell the validation subsystem that the field is only valid if there is a value (any value) in there. If this flag fails, then the validation for that field halts until there is a value.
The validation parameter for the {form-input}, {form-select} and {form-textarea} macros take the following values:
| Validator | Requirement | Invalid Message |
|---|---|---|
| alpha | a-z / A-Z | This field can only contain letters. |
| num | 0-9 | This field can only contain numbers. |
| alphanum | a-z / A-Z / 0-9 | This field can only contain letters and numbers. |
| Email Address | Invalid Email Address. |
If validation fails, the invalid CSS class is added to the offending field and, if attempting to submit, then a message box listing the errors and their corresponding field names is shown.
Please add issues for any validators that you need – if you can include JS code then that's even better.
Available Velocity Context
When rendering a VTL value (via the vtlValue parameter or when using render=velocity) you will want to know what context variables are available:
| Variable | Injected By | Value |
|---|---|---|
| $user | Form Mail NG | AuthenticatedUserThreadLocal.getUser() |
| $ceo | Form Mail NG | ((PageContext) renderContext).getEntity() |
| $req | Confluence | HTTPServletRequest |
There may be more, as the context is initialised with MacroUtils.getDefaultVelocityContext(), so please see the Confluence documentation for more information.
Data Handlers
These are called Collector Types in the code, and refer to the process that is applied when data is submitted.
Email Relay
This is what Form Mail is all about, and is the only collector which supports encryption at the moment. This will take the submission, convert it into a Mail object and hand it to Confluence to mail off to the recipient.
This handler has 3 special fields, and if multiple fields share the same special field name then the value from the last one is used. None of these special fields are required or validated on the server.
| Field Name | Description |
|---|---|
| subject | This becomes the Email's subject |
| from | This becomes the Email's from address |
| from-name | This becomes the Email's from name |
All remaining fields will go into the Email body in a "fieldName: fieldValue\n" layout.
Bandana Store
| In Progress This is new to Form Mail NG, and places the data (held in a MailShuttle) into a BandanaCollector store. The access for the Bandana Stores is somewhat primitive at the moment, but that is a work in progress. As such please treat this option as experimental. |
The idea is that instead of collecting information and sending to a mailbox, you can keep it on the server inside of Confluence. This has the advantages of being easy to access as well as potentially being accessible to extensions to the plugin for automatic processes.
One such extension might be to take details of evaluators of a product / service, the information for which is in the success HTML. You could write a nightly job to poke through the collector to email out a follow up message 1 month after registering for the evaluation.
PGP Cryptography
Java Cryptographic Extensions
| Limited Liability The following instructions are required by the Cryptix JCE provider and you follow them at your own risk. I hold no responsibility for the accuracy or reliability of these instructions. It should be strongly noted that the communication between the web browser and the server stands to be the weakest link, and in this case should always use SSL as if the data is worth encrypting on the server, it's worth encrypting on it's way there. Having said that, they've worked fine for me! |
There may be cases where you wish to store the data in an encrypted form using standard Public Key Infrastructure (PKI). This may be because you are asking the user to transmit credit card details, this may be because you are storing sensitive data which may be covered under a NDA. Whatever the reason, you are in need of an industry standard level of encryption.
In order to use the cryptographic functions of this plugin, you will need to do two things:
- Install the 4 cryptix jar files into confluence/WEB-INF/lib (1, 2, 3, 4)
- Install the "Unlimited Strength Jurisdiction Policy Files" from Sun (involves modifying the JRE)
When these have been performed you can place your public key into the form mail configuration. How this works depends on the collector you have chosen:
- Email Collector
This will cause all emails to be encrypted using that key. The whole email body is encrypted in this manner.
- Bandana Collector
Encryption with this collector is not yet supported, if there is demand a technical solution for it may be sought.
Email Decryption
Well this is a little outside of the scope of this documentation. I would suggest installing OpenPGP and Enigmail for Thunderbird. There is a good article here.
Your OpenPGP public key is what you should be pasting in to this plugin, and you will be using your private key to decrypt it. Keep your private key safe and secure!
Frequently Asked Questions
Here is a list of the most frequently asked questions covering all aspects of the plugin.
I am getting a RuntimeException with the highly descriptive message: NYI
If you are seeing the following error in the logs, then it this typically means you haven't successfully installed the Unlimited Strength Jurisdiction Policy Files in your JRE (CODEGEIST:see above). If you believe you have, make sure that if you have multiple JREs on your system that Confluence is using the right one.
java.lang.RuntimeException: NYI
at cryptix.jce.provider.elgamal.ElGamalCipher.engineGetParameters(ElGamalCipher.java:120)
at javax.crypto.Cipher.a(DashoA12275)
at javax.crypto.Cipher.init(DashoA12275)
at cryptix.openpgp.algorithm.PGPElGamal.encrypt(PGPElGamal.java:550)
at cryptix.openpgp.packet.PGPPubl
Is the baby here yet?
No ... my daughter-to-be is as stuborn as my wife! She seems to want to make an appearance on her own terms. I'll let you all know when she arrives.
Update
She was born a healthy 9lbs 3oz at Warrington General (UK) around 3pm on 11th May 2007. See photos.
Version History
| Version | Date | State | License | Price |
|
|
08 May 2008 | Stable | Freeware / Open Source (BSD) | Donate |
|
|
20 May 2008 | Stable | Freeware / Open Source (BSD) | Donate |
|
|
02 Feb 2008 | Stable | Freeware / Open Source (BSD) | Donate |
|
|
21 Aug 2007 | Stable | Freeware / Open Source (BSD) | Donate |
|
|
14 May 2007 | Stable | Freeware / Open Source (BSD) | Donate |
|
|
08 May 2007 | Stable | Freeware / Open Source (BSD) | Donate |
|
|
07 May 2007 | Stable | Freeware / Open Source (BSD) | Donate |


