diff --git a/pom.xml b/pom.xml
index 8723ec5..015e470 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <groupId>org.jvnet.hudson.plugins</groupId>
     <artifactId>plugin</artifactId>
-    <version>1.319</version>
+    <version>1.345</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
 
@@ -57,5 +57,11 @@
       <version>1.8.2</version>
       <scope>test</scope>
     </dependency>
+          
+    <dependency>
+      <groupId>org.codehaus.groovy</groupId>
+      <artifactId>groovy-all</artifactId>
+      <version>1.5.6</version>
+    </dependency> 
   </dependencies>
 </project>
diff --git a/src/main/java/hudson/plugins/emailext/EmailType.java b/src/main/java/hudson/plugins/emailext/EmailType.java
index 20f5f94..e5687df 100644
--- a/src/main/java/hudson/plugins/emailext/EmailType.java
+++ b/src/main/java/hudson/plugins/emailext/EmailType.java
@@ -40,6 +40,11 @@ public class EmailType {
 	 */
 	private boolean sendToRecipientList;
 	
+	/**
+	 * Specifies whether the mail's content should be interpreted as Groovy script
+	 */
+	private boolean script;
+
 	public EmailType(){
 		subject = "";
 		body = "";
@@ -47,6 +52,7 @@ public class EmailType {
 		sendToDevelopers = false;
 		includeCulprits = false;
 		sendToRecipientList = false;
+		script = false;
 	}
 	
 	public String getSubject() {
@@ -104,4 +110,11 @@ public class EmailType {
 		this.recipientList = recipientList;
 	}
 	
+	public boolean isScript() {
+		return script;
+	}
+	
+	public void setScript(boolean script) {
+		this.script = script;
+	}
 }
diff --git a/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java b/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java
index 51d57ed..1d5e2c2 100644
--- a/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java
+++ b/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java
@@ -2,12 +2,7 @@ package hudson.plugins.emailext;
 
 import hudson.Extension;
 import hudson.Launcher;
-import hudson.model.AbstractBuild;
-import hudson.model.AbstractProject;
-import hudson.model.BuildListener;
-import hudson.model.Hudson;
-import hudson.model.Result;
-import hudson.model.User;
+import hudson.model.*;
 import hudson.plugins.emailext.plugins.ContentBuilder;
 import hudson.plugins.emailext.plugins.EmailTrigger;
 import hudson.plugins.emailext.plugins.EmailTriggerDescriptor;
@@ -20,8 +15,7 @@ import hudson.tasks.Notifier;
 import hudson.tasks.Publisher;
 import hudson.util.FormValidation;
 import net.sf.json.JSONObject;
-import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.*;
 
 import javax.mail.Address;
 import javax.mail.Authenticator;
@@ -46,6 +40,10 @@ import java.util.Properties;
 import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import java.nio.charset.Charset;
+
+import org.kohsuke.stapler.QueryParameter;
+import org.kohsuke.stapler.StaplerRequest;
 
 /**
  * {@link Publisher} that sends notification e-mail.
@@ -69,8 +67,10 @@ public class ExtendedEmailPublisher extends Notifier {
 	public static final String PROJECT_DEFAULT_BODY_TEXT = "$PROJECT_DEFAULT_CONTENT";
 
     public static final String CHARSET = "utf-8";
-	
-	public static void addEmailTriggerType(EmailTriggerDescriptor triggerType) throws EmailExtException {
+    
+    private static final String DEFAULT_CHARSET_SENTINAL = "default";
+
+    public static void addEmailTriggerType(EmailTriggerDescriptor triggerType) throws EmailExtException {
 		if(EMAIL_TRIGGER_TYPE_MAP.containsKey(triggerType.getMailerId()))
 			throw new EmailExtException("An email trigger type with name " +
 					triggerType.getTriggerName() + " was already added.");
@@ -116,6 +116,11 @@ public class ExtendedEmailPublisher extends Notifier {
 	public String contentType;
 
 	/**
+     * The charset of the emails for this project.
+     */
+    public String charset;
+
+	/**
 	 * The default subject of the emails for this project.  ($PROJECT_DEFAULT_SUBJECT)
 	 */
 	public String defaultSubject;
@@ -125,6 +130,10 @@ public class ExtendedEmailPublisher extends Notifier {
 	 */
 	public String defaultContent;
 	
+	public boolean defaultContentIsScript;
+
+    public String buildForTesting;
+
 	/**
 	 * Get the list of configured email triggers for this project.
 	 */
@@ -262,8 +271,7 @@ public class ExtendedEmailPublisher extends Notifier {
 			msg.setFrom(new InternetAddress(ExtendedEmailPublisher.DESCRIPTOR.getAdminAddress()));
 		}
 
-        // Set the contents of the email
-
+		//Set the contents of the email
         msg.setSentDate(new Date());
 
         setSubject( type, build, msg );
@@ -321,18 +329,37 @@ public class ExtendedEmailPublisher extends Notifier {
 		return msg;
 	}
 
+    private static boolean isNullOrBlank(String s) { // or, add dependency on commons-lang StringUtils instead?
+        return s == null || s.trim().length() == 0;
+    }
+
+    private String getCharset() {
+        String cs = charset;
+        if (isNullOrBlank(cs) || DEFAULT_CHARSET_SENTINAL.equalsIgnoreCase(cs)) {
+            cs = DESCRIPTOR.getDefaultCharset();
+        }
+        if (isNullOrBlank(cs) || DEFAULT_CHARSET_SENTINAL.equalsIgnoreCase(cs)) {
+            return CHARSET;
+        } else {
+            return cs;
+        }
+    }
+
     private void setSubject( final EmailType type, final AbstractBuild<?, ?> build, MimeMessage msg )
         throws MessagingException
     {
         String subject = new ContentBuilder().transformText(type.getSubject(), this, type, (AbstractBuild)build);
-        msg.setSubject(subject, CHARSET);
+        msg.setSubject(subject, getCharset());
     }
 
     private void setContent( final EmailType type, final AbstractBuild<?, ?> build, MimeMessage msg )
         throws MessagingException
     {
         final String text = new ContentBuilder().transformText(type.getBody(), this, type, (AbstractBuild)build);
+        msg.setContent(text, getContentType());
+    }
 
+    private String getContentType() {
         String messageContentType = contentType;
         // contentType is null if the project was not reconfigured after upgrading.
         if (messageContentType == null || "default".equals(messageContentType)) {
@@ -343,9 +370,8 @@ public class ExtendedEmailPublisher extends Notifier {
                 messageContentType = "text/plain";
             }
         }
-        messageContentType += "; charset=" + CHARSET;
-
-        msg.setContent(text, messageContentType);
+        messageContentType += "; charset=" + getCharset();
+        return messageContentType;
     }
 
     private static void addAddress(List<InternetAddress> addresses, String address, BuildListener listener) {
@@ -423,6 +449,11 @@ public class ExtendedEmailPublisher extends Notifier {
 		private String defaultContentType;
 
 		/**
+         * This is a global default charset (mime type) for emails.
+         */
+        private String defaultCharset;
+
+		/**
 		 * This is a global default subject line for sending emails.
 		 */
 		private String defaultSubject;
@@ -432,9 +463,19 @@ public class ExtendedEmailPublisher extends Notifier {
 		 */
 		private String defaultBody;
 
+        /**
+         * This indicates that the global default body or subject line should be evaluated as a script.
+         */
+        private boolean defaultIsScript;
+
+        /**
+         * This just remembers the last build for testing that was saved, for the user's convenience.
+         */
+        public String defaultBuildForTesting;
+
 		private boolean overrideGlobalSettings;
-		
-		@Override
+
+        @Override
 		public String getDisplayName() {
 			return "Editable Email Notification";
 		}
@@ -529,9 +570,13 @@ public class ExtendedEmailPublisher extends Notifier {
 		public String getSmtpPort() {
 			return smtpPort;
 		}
-		
-		public String getDefaultContentType() {
-			return defaultContentType;
+
+        public String getDefaultContentType() {
+            return defaultContentType;
+        }
+
+        public String getDefaultCharset() {
+			return defaultCharset;
 		}
 
         public String getDefaultSubject() {
@@ -541,6 +586,14 @@ public class ExtendedEmailPublisher extends Notifier {
 		public String getDefaultBody() {
 			return defaultBody;
 		}
+
+        public boolean getDefaultIsScript() {
+            return defaultIsScript;
+        }
+
+        public String getDefaultBuildForTesting() {
+            return defaultBuildForTesting;
+        }
 		
 		public boolean getOverrideGlobalSettings() {
 			return overrideGlobalSettings;
@@ -559,10 +612,13 @@ public class ExtendedEmailPublisher extends Notifier {
 			ExtendedEmailPublisher m = new ExtendedEmailPublisher();
 			m.recipientList = listRecipients;
 			m.contentType = formData.getString("project_content_type");
-			m.defaultSubject = formData.getString("project_default_subject");
+			m.charset = formData.getString("project_charset");
+            m.defaultSubject = formData.getString("project_default_subject");
 			m.defaultContent = formData.getString("project_default_content");
-			m.configuredTriggers = new ArrayList<EmailTrigger>();
-			
+            m.defaultContentIsScript = formData.optBoolean("project_default_content_is_script");
+            m.buildForTesting = formData.getString("project_build_for_testing");
+            m.configuredTriggers = new ArrayList<EmailTrigger>();
+
 			// Create a new email trigger for each one that is configured
 			for (String mailerId : EMAIL_TRIGGER_TYPE_MAP.keySet()) {
 				if("true".equalsIgnoreCase(formData.optString("mailer_" + mailerId + "_configured"))) {
@@ -571,7 +627,6 @@ public class ExtendedEmailPublisher extends Notifier {
 					m.configuredTriggers.add(trigger);
 				}
 			}
-			
 			return m;
 		}
 		
@@ -584,6 +639,7 @@ public class ExtendedEmailPublisher extends Notifier {
 			m.setSendToRecipientList(formData.optBoolean(prefix + "sendToRecipientList"));
 			m.setSendToDevelopers(formData.optBoolean(prefix + "sendToDevelopers"));
 			m.setIncludeCulprits(formData.optBoolean(prefix + "includeCulprits"));
+            m.setScript(formData.optBoolean(prefix + "script"));
 			return m;
 		}
 		
@@ -630,12 +686,15 @@ public class ExtendedEmailPublisher extends Notifier {
 			smtpPort = nullify(req.getParameter("ext_mailer_smtp_port"));
 			
 			defaultContentType = nullify(req.getParameter("ext_mailer_default_content_type"));
+            defaultCharset = nullify(req.getParameter("ext_mailer_default_charset"));
 
 			// Allow global defaults to be set for the subject and body of the email
 			defaultSubject = nullify(req.getParameter("ext_mailer_default_subject"));
 			defaultBody = nullify(req.getParameter("ext_mailer_default_body"));
-			
-			overrideGlobalSettings = req.getParameter("ext_mailer_override_global_settings") != null;
+            defaultIsScript = req.getParameter("ext_mailer_default_is_script") != null;
+            defaultBuildForTesting = req.getParameter("ext_mailer_default_build_for_testing");
+
+			overrideGlobalSettings = req.getParameter("ext_mailer_use_global_settings") != null;
 			
 			save();
 			return super.configure(req, formData);
@@ -679,9 +738,129 @@ public class ExtendedEmailPublisher extends Notifier {
 			}
 			return FormValidation.ok();
 		}
-		
-	}
 
+        public FormValidation doCharsetCheck(StaplerRequest req, StaplerResponse rsp, @QueryParameter final String value) throws IOException, ServletException {
+            String charset = nullify(value);
+            if (charset == null || DEFAULT_CHARSET_SENTINAL.equalsIgnoreCase(charset) || Charset.isSupported(charset)) {
+                return FormValidation.ok();
+            } else {
+                return FormValidation.error("unsupported charset");
+            }
+        }
+
+        public FormValidation doBuildForTestingCheck(StaplerRequest req, StaplerResponse rsp, @QueryParameter final String value) throws IOException, ServletException {
+            String buildForTesting = nullify(value);
+            if (buildForTesting == null) {
+                return FormValidation.ok();
+            }
+            try {
+                getBuildForTesting(buildForTesting);
+                return FormValidation.ok();
+            }
+            catch (FormValidation e) {
+                return e;
+            }
+        }
+
+        // validateButton in config.jelly
+        public FormValidation doTestAgainstBuild(StaplerRequest req) throws IOException, ServletException {
+            ExtendedEmailPublisher publisher = new ExtendedEmailPublisher();
+            publisher.contentType = req.getParameter("project_content_type");
+            publisher.charset = req.getParameter("project_charset");
+            publisher.defaultSubject = req.getParameter("project_default_subject");
+            publisher.defaultContent = req.getParameter("project_default_content");
+            publisher.defaultContentIsScript = req.getParameter("project_default_content_is_script") != null;
+            publisher.buildForTesting = req.getParameter("project_build_for_testing");
+            return doTestAgainstBuild(publisher, false, req);
+        }
+
+        // validateButton in global.jelly
+        public FormValidation doGlobalTestAgainstBuild(StaplerRequest req) throws IOException, ServletException {
+            ExtendedEmailPublisher publisher = new ExtendedEmailPublisher();
+            // testing at project level because the corresponding globals are static
+            publisher.contentType = req.getParameter("ext_mailer_default_content_type");
+            publisher.charset = req.getParameter("ext_mailer_default_charset");
+            publisher.defaultSubject = req.getParameter("ext_mailer_default_subject");
+            publisher.defaultContent = req.getParameter("ext_mailer_default_body");
+            publisher.defaultContentIsScript = req.getParameter("ext_mailer_default_is_script") != null;
+            publisher.buildForTesting = req.getParameter("ext_mailer_default_build_for_testing");
+            return doTestAgainstBuild(publisher, true, req);
+        }
+
+        // for iframe callback
+        private String testedEmailText;
+        private String testedEmailContentType;
+
+        private FormValidation doTestAgainstBuild(ExtendedEmailPublisher publisher,
+                                                  boolean globallyResolved,
+                                                  StaplerRequest req
+        ) throws FormValidation {
+            if (nullify(publisher.buildForTesting) == null) {
+                return FormValidation.error("need to specify a build for testing");
+            }
+            testedEmailContentType = publisher.getContentType();
+            AbstractBuild build = getBuildForTesting(publisher.buildForTesting);
+            String subject;
+            if (globallyResolved) {
+                // Work around ContentBuilder.transformText()'s static access of the global subject and body,
+                // which has not been updated before testing.
+                subject = transformResolvedText(publisher.defaultSubject, publisher, build);
+                testedEmailText = transformResolvedText(publisher.defaultContent, publisher, build);
+            } else {
+                subject = transformText(publisher.defaultSubject, publisher, build);
+                testedEmailText = transformText(publisher.defaultContent, publisher, build);
+            }
+            String resultUrl = req.getRequestURI().replace("testAgainstBuild", "testedEmailText")
+                    .replace("globalTestAgainstBuild", "testedEmailText"); // todo: something less hacky?
+            return FormValidation.okWithMarkup("resulting subject: " + subject // todo: subject charset?
+                    + "<br/>resulting body:<br/> <iframe width='100%' height='400px' src='" + resultUrl + "'/>");
+        }
 
+        private static String transformResolvedText(String text, ExtendedEmailPublisher publisher, AbstractBuild build) {
+            return new ContentBuilder().transformResolvedText(publisher.defaultContentIsScript, text, publisher, new EmailType(), build);
+        }
 
+        private static String transformText(String text, ExtendedEmailPublisher publisher, AbstractBuild build) {
+            return new ContentBuilder().transformText(text, publisher, new EmailType(), build);
+        }
+
+        // callback from iframe
+        public void doTestedEmailText(StaplerRequest req, StaplerResponse rsp) throws IOException {
+            rsp.setContentType(testedEmailContentType);
+            rsp.getWriter().write(testedEmailText);
+        }
+
+        private AbstractBuild getBuildForTesting(String buildForTesting) throws FormValidation {
+            int slashIndex = buildForTesting.indexOf('/');
+            if (slashIndex == -1) {
+                throw FormValidation.error("must format as '<jobName>/<buildNumber>'");
+            }
+            String jobName = buildForTesting.substring(0, slashIndex);
+            String buildNumber = buildForTesting.substring(slashIndex + 1);
+            Job job;
+            try {
+                job = (Job) Hudson.getInstance().getItem(jobName);
+            }
+            catch (ClassCastException e) {
+                throw FormValidation.error(jobName + " is not a job");
+            }
+            if (job == null) {
+                throw FormValidation.error(jobName + " job not found");
+            }
+            AbstractBuild build;
+            try {
+                build = (AbstractBuild) job.getBuildByNumber(Integer.valueOf(buildNumber));
+            }
+            catch (NumberFormatException e) {
+                throw FormValidation.error("cannot parse build number: " + e.getMessage());
+            }
+            catch (ClassCastException e) {
+                throw FormValidation.error("not a build: " + e.getMessage());
+            }
+            if (build == null) {
+                throw FormValidation.error("build " + buildNumber + " not found");
+            }
+            return build;
+        }
+	}
 }
diff --git a/src/main/java/hudson/plugins/emailext/plugins/ContentBuilder.java b/src/main/java/hudson/plugins/emailext/plugins/ContentBuilder.java
index 55a7b21..58b6b56 100644
--- a/src/main/java/hudson/plugins/emailext/plugins/ContentBuilder.java
+++ b/src/main/java/hudson/plugins/emailext/plugins/ContentBuilder.java
@@ -1,5 +1,7 @@
 package hudson.plugins.emailext.plugins;
 
+import groovy.text.SimpleTemplateEngine;
+import groovy.text.Template;
 import hudson.model.AbstractBuild;
 import hudson.model.AbstractProject;
 import hudson.plugins.emailext.EmailExtException;
@@ -61,13 +63,23 @@ public class ContentBuilder {
 	
 	public <P extends AbstractProject<P, B>, B extends AbstractBuild<P, B>>
 	String transformText(String origText, ExtendedEmailPublisher publisher, EmailType type, B build) {
-		String newText = origText.replaceAll(PROJECT_DEFAULT_BODY, Matcher.quoteReplacement(publisher.defaultContent))
-		 						 .replaceAll(PROJECT_DEFAULT_SUBJECT, Matcher.quoteReplacement(publisher.defaultSubject))
-								 .replaceAll(DEFAULT_BODY, Matcher.quoteReplacement(ExtendedEmailPublisher.DESCRIPTOR.getDefaultBody()))
-								 .replaceAll(DEFAULT_SUBJECT, Matcher.quoteReplacement(ExtendedEmailPublisher.DESCRIPTOR.getDefaultSubject()));
-						
-		newText = replaceTokensWithContent(newText, publisher, type, build);
-		return newText;
+        boolean isScript = type.isScript();
+		String projectlyResolvedText = origText.replaceAll(PROJECT_DEFAULT_BODY, Matcher.quoteReplacement(publisher.defaultContent))
+		 						 .replaceAll(PROJECT_DEFAULT_SUBJECT, Matcher.quoteReplacement(publisher.defaultSubject));
+        boolean usingSomeProjectDefaultContent = !projectlyResolvedText.equals(origText);
+        isScript |= publisher.defaultContentIsScript && usingSomeProjectDefaultContent;
+        String globallyResolvedText = projectlyResolvedText.replaceAll(DEFAULT_BODY, Matcher.quoteReplacement(ExtendedEmailPublisher.DESCRIPTOR.getDefaultBody()))
+                .replaceAll(DEFAULT_SUBJECT, Matcher.quoteReplacement(ExtendedEmailPublisher.DESCRIPTOR.getDefaultSubject()));
+        boolean usingSomeGlobalDefaultContent = !globallyResolvedText.equals(projectlyResolvedText);
+        isScript |= ExtendedEmailPublisher.DESCRIPTOR.getDefaultIsScript() && usingSomeGlobalDefaultContent;
+        return transformResolvedText(isScript, globallyResolvedText, publisher, type, build);
+    }
+
+    // exposed for testing
+    public <P extends AbstractProject<P, B>, B extends AbstractBuild<P, B>>
+    String transformResolvedText(boolean isScript, String text, ExtendedEmailPublisher publisher, EmailType type, B build) {
+		return isScript ? transformUsingScript(text, publisher, type, build)
+		                       : replaceTokensWithContent(text, publisher, type, build);
 	}
 	
 	private static <P extends AbstractProject<P, B>, B extends AbstractBuild<P, B>>
@@ -193,4 +205,34 @@ public class ContentBuilder {
 		
 	}
 
+	private <P extends AbstractProject<P, B>, B extends AbstractBuild<P, B>>
+	String transformUsingScript(String origText, ExtendedEmailPublisher publisher, EmailType type, B build) {
+		SimpleTemplateEngine engine = new SimpleTemplateEngine();
+		Template template = null;
+		try {
+			template = engine.createTemplate(origText);
+			Map binding = new HashMap();
+			Map<String,Object> args = new HashMap<String,Object>();
+			//Setting the AbstractBuild as a bind variable
+			binding.put("build", build);
+
+			//Set all the EmailContent as bind variables to be directly used in the script 
+			for(Map.Entry<String, EmailContent> contentEntry : EMAIL_CONTENT_TYPE_MAP.entrySet()){
+				EmailContent content = contentEntry.getValue();
+				String contentText = content.getContent(build, publisher, type, args);
+				if(content.hasNestedContent()){
+					contentText = replaceTokensWithContent(contentText, publisher, type, build);
+				}
+				binding.put(contentEntry.getKey(), contentText);
+			}
+
+			return template.make(binding).toString();
+		} catch (Exception e) {
+			LOGGER.log(Level.WARNING, "Error creating GroovyTemplate from text ["+origText+"]",e);
+			//Throwing the exception as Runtime as any exception here would mostly (?) be due to incorrect script
+			//and not an expected reason
+			throw new RuntimeException("Error using the template",e);
+		}
+	}
+
 }
diff --git a/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/config.jelly b/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/config.jelly
index 770159b..34dc46c 100644
--- a/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/config.jelly
+++ b/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/config.jelly
@@ -39,6 +39,25 @@
       </select>
     </f:entry>
 
+    <f:entry title="Charset"
+             help="${rootURL}/plugin/email-ext/help/projectConfig/charset.html">
+        <!--input class="setting-input validated" name="project_charset"
+               type="text" value="${instance.charset}"
+               checkUrl="'${rootURL}/publisher/ExtendedEmailPublisher/charsetCheck?value='+encode(this.value)"/-->
+        <j:choose>
+            <j:when test="${instance.configured}">
+                <input class="setting-input validated" name="project_charset"
+                       type="text" value="${instance.charset}"
+                       checkUrl="'${rootURL}/publisher/ExtendedEmailPublisher/charsetCheck?value='+encode(this.value)"/>
+            </j:when>
+            <j:otherwise>
+                <input class="setting-input validated" name="project_charset"
+                       type="text" value="default"
+                       checkUrl="'${rootURL}/publisher/ExtendedEmailPublisher/charsetCheck?value='+encode(this.value)"/>
+            </j:otherwise>
+        </j:choose>
+    </f:entry>
+
 	<!-- This is the default subject line for the project. -->
     <f:entry title="Default Subject"
              help="/plugin/email-ext/help/projectConfig/defaultSubject.html">
@@ -54,6 +73,19 @@
         </j:choose>
     </f:entry>
 
+    <f:entry title="Default Content is Script"
+	     help="${rootURL}/plugin/email-ext/help/projectConfig/mailType/script.html">
+	<j:choose>
+	    <j:when test="${instance.configured}">
+		<f:checkbox name="project_default_content_is_script"
+			    checked="${instance.defaultContentIsScript}" />
+	    </j:when>
+	    <j:otherwise>
+		<f:checkbox name="project_default_content_is_script" checked="false" />
+	    </j:otherwise>
+	</j:choose>
+    </f:entry>
+
 	<!-- This is the default content for the project. -->
     <f:entry title="Default Content"
              help="/plugin/email-ext/help/projectConfig/defaultBody.html">
@@ -87,7 +119,16 @@
 		<td colspan="2"><div id="${secId}contentTokenHelpConf" class="help" style="display:none">${contentTokenText}</div></td>
 		<td></td>
 	</tr>
-	
+
+    <f:entry title="Build for Testing"
+             help="${rootURL}/plugin/email-ext/help/projectConfig/buildForTesting.html">
+        <input class="setting-input validated" name="project_build_for_testing"
+                type="text" value="${instance.buildForTesting}"
+                checkUrl="'${rootURL}/publisher/ExtendedEmailPublisher/buildForTestingCheck?value='+encode(this.value)"/>
+    </f:entry>
+
+    <f:validateButton  title="${%Test Against Build}" method="testAgainstBuild" with="project_build_for_testing,project_default_content_is_script,project_default_content,project_default_subject,project_charset,project_content_type,recipientlist_recipients" />
+
 	<!-- Configure advanced properties like per-build-result status email contents, 
 		 whether or not to send email to developers who made changes, and whether or
 		 not to send email to the global list of devs-->
diff --git a/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/global.jelly b/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/global.jelly
index 28c11f1..438e71c 100644
--- a/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/global.jelly
+++ b/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/global.jelly
@@ -57,6 +57,12 @@
             >HTML (text/html)</f:option>
         </select>
       </f:entry>
+      <f:entry title="Default Charset"
+               help="${rootURL}/plugin/email-ext/help/globalConfig/defaultCharset.html">
+          <input class="setting-input validated" name="ext_mailer_default_charset"
+                 type="text" value="${descriptor.defaultCharset}"
+                 checkUrl="'${rootURL}/publisher/ExtendedEmailPublisher/charsetCheck?value='+encode(this.value)"/>
+      </f:entry>
       <f:entry title="Default Subject"
                help="/plugin/email-ext/help/globalConfig/defaultSubject.html">
         <input class="setting-input" name="ext_mailer_default_subject"
@@ -68,6 +74,21 @@
                     name="ext_mailer_default_body"
                     value="${descriptor.defaultBody}"/>
       </f:entry>
+      <f:entry title="Default is Script"
+               help="${rootURL}/plugin/email-ext/help/globalConfig/defaultIsScript.html">
+          <f:checkbox name="ext_mailer_default_is_script" checked="${descriptor.defaultIsScript}" />
+      </f:entry>
+
+      <f:entry title="Build for Testing"
+               help="${rootURL}/plugin/email-ext/help/globalConfig/buildForTesting.html">
+          <input class="setting-input validated" name="ext_mailer_default_build_for_testing"
+                 type="text" value="${descriptor.defaultBuildForTesting}"
+                 checkUrl="'${rootURL}/publisher/ExtendedEmailPublisher/buildForTestingCheck?value='+encode(this.value)"/>
+      </f:entry>
+
+      <f:validateButton  title="${%Test Against Build}" method="globalTestAgainstBuild"
+                         with="ext_mailer_default_build_for_testing,ext_mailer_default_is_script,ext_mailer_default_subject,ext_mailer_default_body,ext_mailer_default_charset,ext_mailer_default_content_type" />
+
       <!-- This is the help section.  It displays a bunch of dynamic help for all content tokens. -->
       <tr>
         <td></td>
diff --git a/src/main/resources/hudson/plugins/emailext/tags/mailtype.jelly b/src/main/resources/hudson/plugins/emailext/tags/mailtype.jelly
index a0e0e85..aa4d03d 100644
--- a/src/main/resources/hudson/plugins/emailext/tags/mailtype.jelly
+++ b/src/main/resources/hudson/plugins/emailext/tags/mailtype.jelly
@@ -123,6 +123,11 @@
 						name="mailer_${mailType}_body"
 						value="${mailTypeObj.body}"/>
 				</f:entry>
+				<f:entry title="Content is Script"
+					help="${rootURL}/plugin/email-ext/help/projectConfig/mailType/script.html">
+					<f:checkbox name="mailer_${mailType}_script"
+						checked="${mailTypeObj.script}" />
+				</f:entry>
 			</table>
 		</td>
 	</tr>
diff --git a/src/main/webapp/help/globalConfig/buildForTesting.html b/src/main/webapp/help/globalConfig/buildForTesting.html
new file mode 100644
index 0000000..017db19
--- /dev/null
+++ b/src/main/webapp/help/globalConfig/buildForTesting.html
@@ -0,0 +1,3 @@
+<div>
+    Specifies the build used by the Test Against Build button.  Example: common/12
+</div>
diff --git a/src/main/webapp/help/globalConfig/defaultCharset.html b/src/main/webapp/help/globalConfig/defaultCharset.html
new file mode 100644
index 0000000..9f73c3c
--- /dev/null
+++ b/src/main/webapp/help/globalConfig/defaultCharset.html
@@ -0,0 +1,4 @@
+<div>
+    The default charset of the emails sent after a build.
+    If this is set to "default", then it uses UTF-8.
+</div>
diff --git a/src/main/webapp/help/globalConfig/defaultIsScript.html b/src/main/webapp/help/globalConfig/defaultIsScript.html
new file mode 100644
index 0000000..45ba123
--- /dev/null
+++ b/src/main/webapp/help/globalConfig/defaultIsScript.html
@@ -0,0 +1,4 @@
+<div>
+    Indicates that the global default subject or content includes a script.
+    If they are used within an email, the whole email will be evaluated as a script.
+</div>
diff --git a/src/main/webapp/help/projectConfig/buildForTesting.html b/src/main/webapp/help/projectConfig/buildForTesting.html
new file mode 100644
index 0000000..017db19
--- /dev/null
+++ b/src/main/webapp/help/projectConfig/buildForTesting.html
@@ -0,0 +1,3 @@
+<div>
+    Specifies the build used by the Test Against Build button.  Example: common/12
+</div>
diff --git a/src/main/webapp/help/projectConfig/charset.html b/src/main/webapp/help/projectConfig/charset.html
new file mode 100644
index 0000000..a30d9bf
--- /dev/null
+++ b/src/main/webapp/help/projectConfig/charset.html
@@ -0,0 +1,4 @@
+<div>
+    The charset of the emails sent after a build.  If this is set
+    to "default", then it uses the value set on the main configuration page.
+</div>
diff --git a/src/main/webapp/help/projectConfig/mailType/script.html b/src/main/webapp/help/projectConfig/mailType/script.html
new file mode 100644
index 0000000..c97b9fd
--- /dev/null
+++ b/src/main/webapp/help/projectConfig/mailType/script.html
@@ -0,0 +1,6 @@
+<div>
+	Specifies whether the mail's content should be interpreted as a Groovy
+	<a href="http://groovy.codehaus.org/Groovy+Templates">SimpleTemplate</a> script.
+	If so, the script can access the <code>AbstractBuild</code> object using the
+	<code>build</code> bind variable.
+</div>
diff --git a/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherTest.java b/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherTest.java
index f3fd4fc..5591cd2 100644
--- a/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherTest.java
+++ b/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherTest.java
@@ -254,9 +254,11 @@ public class ExtendedEmailPublisherTest
     {
         JSONObject form = new JSONObject();
         form.put( "project_content_type", "default" );
+        form.put( "project_charset", "default" );
         form.put( "recipientlist_recipients", "ashlux@gmail.com" );
         form.put( "project_default_subject", "Make millions in Nigeria" );
         form.put( "project_default_content", "Give me a $1000 check and I'll mail you back $5000!!!" );
+        form.put( "project_build_for_testing", "" );
 
         publisher = (ExtendedEmailPublisher) ExtendedEmailPublisher.DESCRIPTOR.newInstance( null, form );
 
diff --git a/src/test/java/hudson/plugins/emailext/plugins/ContentBuilderTest.java b/src/test/java/hudson/plugins/emailext/plugins/ContentBuilderTest.java
index 6b98b0c..33b91c8 100644
--- a/src/test/java/hudson/plugins/emailext/plugins/ContentBuilderTest.java
+++ b/src/test/java/hudson/plugins/emailext/plugins/ContentBuilderTest.java
@@ -1,6 +1,7 @@
 package hudson.plugins.emailext.plugins;
 
 import hudson.model.AbstractBuild;
+import hudson.plugins.emailext.EmailType;
 import hudson.plugins.emailext.ExtendedEmailPublisher;
 import org.jvnet.hudson.test.HudsonTestCase;
 
@@ -146,18 +147,18 @@ public class ContentBuilderTest
     public void testTransformText_shouldExpand_$PROJECT_DEFAULT_CONTENT()
         throws IOException, InterruptedException
     {
-        assertEquals(publisher.defaultContent, new ContentBuilder().transformText( "$PROJECT_DEFAULT_CONTENT", publisher, null,
+        assertEquals(publisher.defaultContent, new ContentBuilder().transformText( "$PROJECT_DEFAULT_CONTENT", publisher, new EmailType(),
                                                        mock( AbstractBuild.class ) ));
-        assertEquals(publisher.defaultContent, new ContentBuilder().transformText( "${PROJECT_DEFAULT_CONTENT}", publisher, null,
+        assertEquals(publisher.defaultContent, new ContentBuilder().transformText( "${PROJECT_DEFAULT_CONTENT}", publisher, new EmailType(),
                                                        mock( AbstractBuild.class ) ));
     }
 
     public void testTransformText_shouldExpand_$PROJECT_DEFAULT_SUBJECT()
         throws IOException, InterruptedException
     {
-        assertEquals(publisher.defaultSubject, new ContentBuilder().transformText( "$PROJECT_DEFAULT_SUBJECT", publisher, null,
+        assertEquals(publisher.defaultSubject, new ContentBuilder().transformText( "$PROJECT_DEFAULT_SUBJECT", publisher, new EmailType(),
                                                        mock( AbstractBuild.class ) ));
-        assertEquals(publisher.defaultSubject, new ContentBuilder().transformText( "${PROJECT_DEFAULT_SUBJECT}", publisher, null,
+        assertEquals(publisher.defaultSubject, new ContentBuilder().transformText( "${PROJECT_DEFAULT_SUBJECT}", publisher, new EmailType(),
                                                        mock( AbstractBuild.class ) ));
     }
 
@@ -165,10 +166,10 @@ public class ContentBuilderTest
         throws IOException, InterruptedException
     {
         assertEquals( ExtendedEmailPublisher.DESCRIPTOR.getDefaultBody(),
-                      new ContentBuilder().transformText( "$DEFAULT_CONTENT", publisher, null,
+                      new ContentBuilder().transformText( "$DEFAULT_CONTENT", publisher, new EmailType(),
                                                           mock( AbstractBuild.class ) ) );
         assertEquals( ExtendedEmailPublisher.DESCRIPTOR.getDefaultBody(),
-                      new ContentBuilder().transformText( "${DEFAULT_CONTENT}", publisher, null,
+                      new ContentBuilder().transformText( "${DEFAULT_CONTENT}", publisher, new EmailType(),
                                                           mock( AbstractBuild.class ) ) );
     }
 
@@ -176,10 +177,10 @@ public class ContentBuilderTest
         throws IOException, InterruptedException
     {
         assertEquals( ExtendedEmailPublisher.DESCRIPTOR.getDefaultSubject(),
-                      new ContentBuilder().transformText( "$DEFAULT_SUBJECT", publisher, null,
+                      new ContentBuilder().transformText( "$DEFAULT_SUBJECT", publisher, new EmailType(),
                                                           mock( AbstractBuild.class ) ) );
         assertEquals( ExtendedEmailPublisher.DESCRIPTOR.getDefaultSubject(),
-                      new ContentBuilder().transformText( "${DEFAULT_SUBJECT}", publisher, null,
+                      new ContentBuilder().transformText( "${DEFAULT_SUBJECT}", publisher, new EmailType(),
                                                           mock( AbstractBuild.class ) ) );
     }
 }