Razor views as email templates - templates

I am creating an email engine in mvc3 and I am trying to use razor views as email templates.
I heard this is possible but I have not yet found any information about it.

You can use http://razorengine.codeplex.com/ to achieve this. It allows you to use razor outside of mvc.
string Email = "Hello #Model.Name! Welcome to Razor!";
string EmailBody = Razor.Parse(Email, new { Name = "World" });
It's simple to implement and it's available on http://nuget.codeplex.com/ for easy integration into your projects.

You CAN use a template file to serve as a razor email body template. You can use whichever extension you choose because you can load a file as text in .Net. Let's use the following example for the template:
Hello #Model.Name,
Welcome to #Model.SiteName!
Regards,
Site Admins
Save that file as something like "WelcomeMessage.cshtml", "WelcomeMessage.template", etc. Select the file in Solution Explorer and in the Properties window, select "Copy to Output Directory" and choose "Copy Always". The only down point is that this template has to accompany the application and doesn't compile as a class.
Now we want to parse it as a string to assign to a mail message body. Razor will take the template and a model class, parse them, and then return a string with the necessary values.
In your application you will need to add the RazorEngine package which can be found with NuGet. Here's a short code example to illustrate the usage:
using System.IO;
using RazorEngine;
// ...
MyModel model = new MyModel { Name = "User", SiteName = "Example.com" };
string template = File.OpenText("WelcomeMessage.template").ReadToEnd();
string message = Razor.Parse(template, model);
It's similar to the other answers but shows a quick way to load the template from a text file.

You should perhaps consider MvcMailer. RazorEngine is (very) good if you aren't already using MVC (I've used it successfully in a webforms context), but if you have MVC you may as well take advantage of it.
(via Hanselmen's NuGet package of the week 2)

You can also use Essential Mail: Razor package from NuGet. It is build over RazorEngine and provides simple interface for email rendering.
Email message template looks something like
#inherits Essential.Templating.Razor.Email.EmailTemplate
#using System.Net;
#{
From = new MailAddress("example#email.com");
Subject = "Email Subject";
}
#section Html
{
<html>
<head>
<title>Example</title>
</head>
<body>
<h1>HTML part of the email</h1>
</body>
</html>
}
#section Text
{
Text part of the email.
}
Read more on GitHub: https://github.com/smolyakoff/essential-templating/wiki/Email-Template-with-Razor

Mailzor
Linked to what #thiagoleite mentioned, I took Kazi Manzur Rashid's idea (with permission) and extended in to be more friendly for how I wanted to use it.
So check out the github project 'mailzor'
It's also up on Nuget.org/packages/mailzor

Related

Extending template blocks in Phoenix framework for custom css/js in the templates [duplicate]

I am looking to add additional layout parameters like the #inner for the layout. For example #title for the <title>#title</title> and an area for onload javascript for individual pages.
window.onload = function () {
#onload_js
}
These are set in the layout, so I am not sure the best way to handle these in Phoenix. Thanks :D.
For the page title, you can simply pass a value through from your controller:
def edit(conn, params) do
render(conn, "edit.html", page_title: "Edit The Thing")
end
<head>
<title><%= assigns[:page_title] || "Default Title" %></title>
</head>
Note that this uses assigns[:page_title] instead of #page_title or assigns.page_title as they will error if the :page_title key is not present in assigns.
For including templates (your script example) there is render_existing/3 (and the docs for the same function in the latest version of Phoenix).
The documentation gives a similar example to what you requested so I have copied it here for convenience:
Consider the case where the application layout allows views to dynamically render a section of script tags in the head of the document. Some views may wish to inject certain scripts, while others will not.
<head>
<%= render_existing view_module(#conn), "scripts.html", assigns %>
</head>
Then the module for the #inner view can decide to provide scripts with either a precompiled template, or by implementing the function directly, ie:
def render("scripts.html", _assigns) do
"<script src="...">"
end
To use a precompiled template, create a scripts.html.eex file in the templates directory for the corresponding view you want it to render for. For example, for the UserView, create the scripts.html.eex file at web/templates/user/.

How to replace all anchor tags with a different anchor using regex in ColdFusion

I found a similar question here: Wrap URL within a string with a href tags using Coldfusion
But what I want to do is replace tags with a slightly modified version AFTER the user has submitted it to the server. So here is some typical HTML text that the user will submit to the server:
<p>Terminator Genisys is an upcoming 2015 American science fiction action film directed by Alan Taylor. You can find out more by clicking here</p>
What I want to do is replace the <a href=""> part with a new version which would be like this:
...
clicking here
So I'm just adding the text rel="nofollow noreferrer" to the tag.
I must match anchor tags that contain a href attribute with a URL, not just the URL string itself, because sometimes a user could just do this:
<p>Terminator Genisys is an upcoming 2015 American science fiction action film directed by Alan Taylor. You can find out more by http://www.imdb.com</p>
In which case I still only want to replace the tag. I don't want to touch the actual anchor text used even though it is a URL.
So how could I rewrite this Regex
#REReplaceNoCase(myStr, "(\bhttp://[a-z0-9\.\-_:~###%&/?+=]+)", "\1", "all")#
the other way round, where its selecting tags and replacing them with my modified text?
If you're willing, this is a really easy task for jQuery (client-side)
JSFiddle: http://jsfiddle.net/mz1rwo0u/
$(document).ready(function () {
$("a").each(function(e) {
if ($(this).attr('href').match(/^https?:\/\/(www\.)?imdb\.com/i)) {
$(this).attr('rel','nofollow noreferrer');
}});
});
(If you right click any of the imdb links and Inspect Element, you'll see the rel attribute is added to the imdb links. Note that View Source won't reflect the changes, but Inspect Element is the important part.)
If you want to effect every a link, you can do this.
$(document).ready(function () {
$("a").each(function(e) {
$(this).attr('rel','nofollow noreferrer');
});
});
Finally, you can also use a selector to narrow it down, you might have the content loading into a dom element with the id contentSection. You can do...
$(document).ready(function () {
$("#contentSection a").each(function(e) {
if ($(this).attr('href').match(/^https?:\/\/(www\.)?imdb\.com/i)) {
$(this).attr('rel','nofollow noreferrer');
}});
});
It's a bit tougher to reliably parse this in cold fusion without the possibility of accidentally adding it twice (without invoking a tool like jSoup) but the jQuery version is client-side and works by obtaining data from the DOM rather than trying to hot-wire into it (a jSoup implementation works similarly, creating a DOM-like structure you can work with).
When talking about client-side vs server-side, you have to consider the mythical user who doesn't have javascript enabled (or who turns it off with malicious intent). If this functionality is not mission-critical. I'd use JQuery to do it. I've used similar functionality to pop an alert box when the user clicks an outside link on one of my sites.
Here's a jSoup implementation, quick and dirty. jSoup is great for how it selects similarly to jQuery.
<cfscript>
jsoup = CreateObject("java", "org.jsoup.Jsoup");
HTMLDocument = jsoup.parse("<A href='http://imdb.com'>test</a> - <A href='http://google.com'>google</a>");
As = htmldocument.select("a");
for (link in As) {
if (reFindnoCase("^https?:\/\/(www\.)?imdb\.com",link.attr("href"))) {
link.attr("rel","nofollow noreferrer");
}
}
writeOutput(htmldocument);
</cfscript>

Smarty include template in both php and javascript (using Smarty and JSmart)

I am trying to use a single smarty template in both PHP and JavaScript. This works great but I'm trying to figure out how I can use an {include file=""} tag in the template when the JavaScript side expects an element ID and the PHP side expects a file path?
Do the element IDs have to match the path I will use when on the PHP side?
OK I worked out how to do this, I overwrote the js prototype method for jsmart that requests a template by id:
jSmart.prototype.getTemplate = function () {}; // Add your method here
That way I can control what to do with the id including mapping it to a template element with a different ID from the passed path.
I know this question looks old, but would like to answer your question since I came across this question via Google and may happen with many others.
xyz.tpl - Template to be included.
Hello {$name}
pqr.tpl - parent template.
There you see the message
{include file='./xyz.tpl'}
Now in Javascript section of a web page define
jSmart.prototype.getTemplate = function (name) {
// Load template content here of template 'name' via ajax or DOM. Say here in the e.g. it would be './xyz.tpl'.
};
Now just call the parent template
<script>
var tplData = <content of pqr.tpl>; // You can load data in this via ajax or from DOM.
var tplObj = new jSmart(tplData);
var output = tplObj.fetch({'name': 'World'});
alert(output);
</script>
Source:-
https://github.com/umakantp/jsmart/wiki/Include-Templates

backbone/marionette attaching HTML into a region

I'm beginning to use Marionette within an existing backbone application. I've got some HTML which I want to append into a region. In pure backbone, I could just do this.$el.append(html_code) and that was all. As far as I can see, marionette regions allow only to operate on views (which have to implement the render method). Calling append on marionette region throws 'undefined method' errors.
Is it possible to attach plain HTML to a marionette region?
No, it's not possible to inject plain html into a Marionette.Region.
Theoretically you could access a regions DOM element with someRegion.el or someRegion.getElement(), but this must be done after rendering (which at least isn't possible inside a Marionette.View with standard behaviour).
But you can achieve the desired result by using a specially crafted Marionette.ItemView:
#someRegion.show(new Marionette.ItemView({template: '<h1>gach</h1>'}));
You maybe also should have a look at Marionette.Renderer .
a Marionette ItemView will look for a template and will call render on that template, so when you show the view in the region the html will be displayed just fine with out the need of you defining a render method.
MyImtemView = Backbone.Marionete.ItemView.extend({
template : "#myTemplate"
});
var myItemView = new MyItemView();
myLayout.aregion.show(myItemview);
this should work if you save your html in a template like this
`<script id="myTemplate" type="text/template">
<div><p>your html<p>
</div>
`
EDIT
you can also declare a render function in your view in case you need to generate and modify your html like this.
MyImtemView = Backbone.Marionete.ItemView.extend({
template : "#myTemplate",
render : function (){
this.$el.append(HMTL); //so here you work your html as you need
}
});
var myItemView = new MyItemView();
myLayout.aregion.show(myItemview); //the render function of your view will be called here
I ran into the same problem and tried the answers explained here, but I'm also using require.js and kept getting an error for the #my_view template not being found. If anyone can clarify where does Marionette look up the templates by default, that would be great.
Instead, I solved it by using the text.js plugin for underscore.js. This way you actually can use a plain html file as the template, without the need for nesting it in a script tag. Here's how I did it.
define(['backbone', 'underscore', 'marionette', 'text!tmpl/my_view.html'], function(Backbone, _, Marionette, view_t){
var MyView = Backbone.Marionette.ItemView.extend({
template : function(serialized_model) {
//define your parameters here
param1 = erialized_model.param1;
return _.template(view_t)({
param1: param1
});
}
});
return MyView;
});
I placed the text.js plugin in the same lib directory as all my other js libraries and my main.js for require declares the path to the templates as
'tmpl': '../../templates',
My project structure looks like this
root
index.html
js
main.js
app
App.js
views
MyView.js
lib
require.js
text.js
backbone.js
underscore.js
jquery.js
backbone.marionette.js
templates
my_view.html
My template 'my_view.html' simply looks like this.
<h1>THIS IS FROM THE TEMPLATE!!!</h1>
Worked perfectly. I hope you find it useful.
Using a view
var myHtml = '<h1>Hello world!</h1>';
var myView = new Marionette.ItemView({template: _.constant(myHtml)});
myRegion.show(myView);
Marionette.Renderer.render takes either a function or the name of a template (source code). _.constant creates a function that returns the passed-in parameter.
Attaching HTML
Alternately, the docs for Marionette.Region mention overriding the attachHtml method, see Set How View's el Is Attached.

Attaching a .png file to an email sent by satchmo

In a Satchmo Store, I need to attach a small .png (a barcode) to an email that django sends on completion of the order. The email is formatted in HTML using send_order_confirmation() which calls send_store_mail() (both part of satchmo.) Neither of these functions offer the ability to attach a file (I think) so should I just re-write them? I was wondering if it is possible/better to do this using signals. Maybe rendering_store_mail() ?
By the way, the barcode would be dynamically generated, so there's no way of having a link to a file on a server somewhere.
Many thanks,
Thomas
well I too had to add extra infos to the confirmation emails, only text though. So this would be the very easy way to add extra-stuff to emails using signals, which IMHO, is the best approach to do it. Always use signals if you can avoid overriding the satchmo-core ;-)
define your listener to add some context for the rendering. In this case I'm adding the contents of an extra notes field, and the barcode for this order, supposing there is a function named get_barcode_img(<order>), to the context. I'm supposing here too, that the get_barcode_img function would return not just a png, but something like a MIMEImage (like from email.MIMEImage import MIMEImage) to be able to just include it inline. Also, there might be more infos needed, like a MIME-header for the img.
# localsite/payment/listeners.py
def add_extra_context_to_store_mail(sender,
send_mail_args={}, context={}, **kwargs):
if not 'order' in context:
return
context['barcode_header'] = get_barcode_header(context['order'])
context['barcode_img'] = get_barcode_img(context['order'])
context['notes'] = context['order'].notes
connect the listener to the signal somewhere where the code will be "discovered" for sure, like models.py:
# localsite/payment/models.py
from satchmo_store.shop.signals import rendering_store_mail, order_notice_sender
rendering_store_mail.connect(payment_listeners.add_extra_context_to_store_mail, sender=order_notice_sender)
override the templates locally (e.g. order_placed_notice.html) to add the new context. Be aware where you put your templates, as the path is essential for django to take your new template instead of the satchmo's one. In this case, starting from your project's root-path, there could be a templates-folder and inside it, there must be exactly the same path as in the satchmo-folder. E.g. /templates/shop/email/order_placed_notice.html ... this can be applied for any "valid" templates-folder inside an app. It's up to you to decide, where/how the templates should be organized.
<!-- templates/shop/email/order_placed_notice.html -->
<!DOCTYPE ...><html>
<head>
<!-- include the image-header here somewhere??? -->
<title></title>
</head>
<body>
...
Your comments:
{{ notes }}
Barcode:
{{ barcode_img }}"