Copying Email Templates:
Novell Identity Manager introduced the idea of Email templates in some version, I cannot recall when exactly it was. Email templates are a great idea, because they let you send an email, and pass in any bit of information you have available via Identity Manager, and let you use place the data into the email. They also allow you to construct them in advance, use HTML and make them much prettier than is easily available, if building them in a send email token, and providing the string in Argument Builder.
Argument Builder is very powerful, but editing and making changes can be quite painful, in terms of rearranging things, after they are laid out. For example, I often find in my Toolkit style rules,
(see the articles here:
- Toolkit Rules in Identity Manager Part 1
- Toolkit Rules in Identity Manager Part 2
- Toolkit Rules in Identity Manager Part 3
- Toolkit Rules in Identity Manager Part 4
- Example of a Use for a Toolkit Rule in Identity Manager
- Another Toolkit Rule Use Example, Bad Attribute Value Cleanup )
that I like to reuse the rule, but going through and editing the message that gets sent by the more simple Send Email action can be quite painful. To the point, unless I intend to show it to other people, I often do not bother cleaning it up too much, since I know what each bit of information is supposed to mean, and it does not need to be easily human readable. (I guess I do not count myself as human in that case.)
Honestly, Argument Builder is meant for building smaller strings, out of text tokens, local variables, values from attributes, etc and not really meant for producing professional looking emails. Now that is not to say it is not possible, but it may not really be worth the extra effort.
There are a couple of interesting things about using the Send Email from Template token that are not entirely obvious from the user interface in Designer and iManager that you let you use the token. First off, the values you can send into the token, called Strings in the interface, look to be either arbitrary or tightly defined. I say that because the line you get for the name of the string is blank and lets you type (thus the arbitrary feeling) and yet provides a drop down list of values like To, from, cc, etc.
In this case it is actually the best of both worlds, since you can use the predefined very common system suggestions from the drop down list, or define your own.
If you define your own string names, then in the Email Template object, stored in the “Default Notification Collection” in the Security container, that is right off the Root of the tree you can add it, via the list in the upper right hand corner, where they are now called tokens, just to be confusing. In this case, you do NOT need to specify a leading and trailing dollar sign ($), it gets added for you.
Once you have a token defined in the email template, and you define a string with a value to be sent from Policy Builder, then where ever you place the string $TokenName$ in the email message, it gets replaced with the value sent when the Send Email from Template action is used.
You can define the email message as text only, or as HTML. This allows a reasonable amount of control over look and feel. To add images, you are best to point at external web links to the images, as adding attached files is pretty awkward to do.
There is even a preview button to let you see what this might look like, of course the data from an event sent via the Strings will not be present yet.
This way you can have a nice company logoed email, set up in a template, with place holders for the user name, the first name, last name, etc, and when the DirXML Script token, send email from template is called, you can pass the values to be filled into the email. This lets you send a pretty customized message to users, based on events, as pretty or as simple as you would like.
You can see some examples in almost all the shipping drivers that support password synchronization events. (I cannot think of one that is missing it, but no doubt if I said in all shipping drivers, someone would point out the one I forgot about!) There is a rule in the Input and Output transform that watches for password synchronization events and in the case of failures or errors, if a Global Configuration Variable (GCV) is set, and the user has an email address attribute populated (Internet EMail Address, note the EM in EMail, there is a typo in schema, and it has been around a VERY long time!) then it will send a message with the error code encountered.
This way you can see the specific use of the Action, along with some of the strings sent along to the email message. You can look at the sample email template that Identity Manager ships with (in multiple languages even!).
Just for fun, here is a sample from the Output transform of a typical Active Directory driver. I think this case from the V5 Active Directory default configuration, (I took it from a production driver, and I am not one hundred percent of exactly where it began life).
<rule> <description>Send e-mail for a failed publish password operation</description> <conditions> <and> <if-global-variable mode="nocase" name="notify-user-on-password-dist-failure" op="equal">true</if-global-variable> <if-operation op="equal">status</if-operation> <if-xpath op="true">self::status[@level != 'success']/operation-data/password-publish-status</if-xpath> </and> </conditions> <actions> <!-- generate email notification --> <do-send-email-from-template notification-dn="Security\Default Notification Collection" template-dn="Security\Default Notification Collection\Password Sync Fail" template-dn-dot-dn="Password Sync Fail.Default Notification Collection.Security"> <arg-string name="UserFullName"> <token-src-attr name="Full Name"> <arg-association> <token-xpath expression="self::status/operation-data/password-publish-status/association"/> </arg-association> </token-src-attr> </arg-string> <arg-string name="UserGivenName"> <token-src-attr name="Given Name"> <arg-association> <token-xpath expression="self::status/operation-data/password-publish-status/association"/> </arg-association> </token-src-attr> </arg-string> <arg-string name="UserLastName"> <token-src-attr name="Surname"> <arg-association> <token-xpath expression="self::status/operation-data/password-publish-status/association"/> </arg-association> </token-src-attr> </arg-string> <arg-string name="ConnectedSystemName"> <token-global-variable name="ConnectedSystemName"/> </arg-string> <arg-string name="to"> <token-src-attr name="Internet EMail Address"> <arg-association> <token-xpath expression="self::status/operation-data/password-publish-status/association"/> </arg-association> </token-src-attr> </arg-string> <arg-string name="FailureReason"> <token-text/> <token-xpath expression="self::status/child::text()"/> </arg-string> </do-send-email-from-template> </actions> </rule>
You can see that the condition,
<if-global-variable mode="nocase" name="notify-user-on-password-dist-failure" op="equal">true</if-global-variable>
tests for the GCV called notify-users-on-password-dist-failure to control whether emails are sent. This is a great approach that allows one rule to be used in many drivers, and controlled with a simple setting.
You get a nice example of how to get attributes of the user referenced in the <status> document that the rule reacts too, when the <status> document by default does not include the distinguished name of the user. This is usually a pain to deal with, and to make it more human readable, most typically, I would add an operation property or two on the Subscriber channel named userDN and event, to add some information to the document of the event type and the DN of the user. This was I can easily read it (as a dubious human) in trace and see what user this event was for, and then by looking at the value of the operation property named “event” see if it was an add, modify, etc event.
You cannot use the Association() token that is in Argument Builder to try and get the association value, since a status document does not have a src-dn or dest-dn and the token does not work on them, though to be fair, I am not sure of what exactly is missing to make the token not work. But looking at the document you can see it does not entirely resemble the usual style of an operation document.
What this rule then does is get the Association value via XPATH, and query back into eDirectory for the attributes of the objects, referenced by the association value.
The token that does this is:
The XPATH looks into the <status> node, then the <operation-data> node, where in the case of password events, the rules in the Subscriber and Publisher Command transform, have added a payload of information that we can now retrieve. To see some of the inner workings of what goes on in those Command Transform rules, that most drivers have, you can read this article that dissects them, line by line:
Password Transformation Rule Sets
Thus the driver can figure out what object was being referred too, via the association value that was added as an operation property and use it to get back some values to send as strings to the send email from template action.
You can see from this example how useful such an action can be, in terms of making it easy to send fancy, personalized emails.
The next problem that comes up when you start working with this in a more real world environment.
When I develop a solution for a customer, I am almost never working in the real production environment. That would be crazy, as along the way during development I often do really really stupid things. That have unintended consequences that might seriously damage a production system, whereas in a lab environment, say hosted in VM’s I can take periodic snapshots of the VM’s and revert back if I realize I did something very foolish.
Far easier to fix these issues in the lab, than in production. Most objects in Identity Manager, in Designer, will have an XML view tab, in which you can see the underlying XML that constructs the object. Even in the case of the driver configuration, where several of the configuration settings are actually stored in different attributes on the driver object, they each still have an XML view that allows you to make changes in XML that are easy and simple, but in the GUI interface would be long and tedious.
Additionally, in the XML view you can copy and paste snippets or the entire XML document from one object to another, or from one project to another. This can be tedious if you tried to do everything by hand as it would take a lot of clicking and opening tabs, but it would be doable.
In the case of Email Templates, alas, there is no XML view to use. This can be frustrating, as you might wish to copy a template to use either in production or to work on a modified copy.
You could use the Export to Configuration File option in Designer to export the template but there is actually another way possible.
When you look in the object view of the the project, where you see the Identity vaults, with servers, driver sets, drivers, channels and rules, you can scroll to the bottom to find the Default Notification Collection. Expand that node, and you can find the email template you were working on. If you right click on that template, you can Edit it, or open with XML editor. Which is the choice to take.
If you open it with the XML editor, all the XML for the template, including the defined tokens with their descriptions is available to copy and paste. The only thing missing is the Subject line of the message since that seems to be stored in a separate attribute, that does not get included in this editor.
Then create a new email template object, just by selecting New from the context menu of the Default Notification Collection node, and once it is created and named, open it with the XML Editor and paste the contents of the previous rule in.
Close the XML Editor and open it with the regular editor and there you have it. Copied and pasted. Fix up the Subject line and you are all done.
You probably could do this via an LDIF export of the object, change the DN in the LDIF file that refers to the object to a new name, and reimport it via LDAP but that is probably a bit more complex than this approach.