I am trying to use the nVelocity #include directive to include a html fragment inside the the email templates, like this:
#include("env.vm")
or
#parse("env.vm")
But, no matter where I put the env.vm file I get this error: Some error has occurred while parsing email template. Please fix the email template 'Customer Order Notification' before trying to send email. Error details:
Unable to find resource 'env.nm'
Does anyone have any idea where I should put these kind of file so nVelocity engine can find it?
Looks like the default TEMPLATE_ROOT is c:\windows\System32. Is there a way to change it?
#include and #parse in email templates
Re: #include and #parse in email templates
For anybody who has this same problem, I was able to get around it by putting the following code in the Init function of a custom http module.
The problem is caused by the CommerceBuilder.Messaging.NVelocityEngine constructor. All it does is create the parent (NVelocity.App.VelocityEngine) and immediately call Init(). Unfortunately, it seems that any properties have to be set before the init function is called. Any properties that aren't explicitly set will just use default values. The default value for the file.resource.loader.path property is "." (the current directory) which is typically "c:\windows\System32".
The code above creates a CommerceBuilder.Messaging.NVelocityEngine object without calling its constructor. Then it calls the constructor for the parent object, sets the file.resource.loader.path property, and initializes the NVelocity engine. Then it replaces the static NVelocityEngine object saved in the CommerceBuilder.Messaging.NVelocityEngine class.
This seems to work correctly for AbleCommerce 7.0.7 but may break in future versions.
Code: Select all
//create new NVelocityEngine object - without calling a constructor
CommerceBuilder.Messaging.NVelocityEngine newEngine = (CommerceBuilder.Messaging.NVelocityEngine)System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(CommerceBuilder.Messaging.NVelocityEngine));
//invoke constructor of parent
typeof(NVelocity.App.VelocityEngine).GetConstructor(new Type[] { }).Invoke(newEngine, null);
//set property and initialize
newEngine.SetProperty("file.resource.loader.path", "C:\\inetpub\\wwwroot\\App_Data\\EmailTemplates\\1\\");
newEngine.Init();
//save newEngine in static private field in NVelocityEngine class
typeof(CommerceBuilder.Messaging.NVelocityEngine).GetField("a", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).SetValue(null, newEngine);
The code above creates a CommerceBuilder.Messaging.NVelocityEngine object without calling its constructor. Then it calls the constructor for the parent object, sets the file.resource.loader.path property, and initializes the NVelocity engine. Then it replaces the static NVelocityEngine object saved in the CommerceBuilder.Messaging.NVelocityEngine class.
This seems to work correctly for AbleCommerce 7.0.7 but may break in future versions.