1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.MonoRail
.Framework
18 using System
.Collections
;
21 using System
.Text
.RegularExpressions
;
22 using Castle
.Components
.Common
.EmailSender
;
24 using Castle
.Core
.Logging
;
27 /// Default implementation of <see cref="IEmailTemplateService"/>
30 /// Will work only during a MonoRail process as it needs a <see cref="IEngineContext"/>
31 /// and a <see cref="Controller"/> instance to execute.
33 public class EmailTemplateService
: IMRServiceEnabled
, IEmailTemplateService
35 private static readonly String HeaderPattern
= @"[ \t]*(?<header>(to|from|cc|bcc|subject|X-\w+)):[ \t]*(?<value>(.)+)(\r*\n*)?";
36 private static readonly Regex HeaderRegEx
= new Regex(HeaderPattern
, RegexOptions
.IgnorePatternWhitespace
| RegexOptions
.IgnoreCase
| RegexOptions
.Compiled
);
37 private static readonly string EmailTemplatePath
= "mail";
40 /// The logger instance
42 private ILogger logger
= NullLogger
.Instance
;
44 private IViewEngineManager viewEngineManager
;
47 /// Initializes a new instance of the <see cref="EmailTemplateService"/> class.
49 public EmailTemplateService()
54 /// Initializes a new instance of the <see cref="EmailTemplateService"/> class.
56 /// <param name="viewEngineManager">The view engine manager.</param>
57 public EmailTemplateService(IViewEngineManager viewEngineManager
)
59 this.viewEngineManager
= viewEngineManager
;
62 #region IMRServiceEnabled
65 /// Invoked by the framework in order to give a chance to
66 /// obtain other services
68 /// <param name="serviceProvider">The service proviver</param>
69 public void Service(IMonoRailServices serviceProvider
)
71 ILoggerFactory loggerFactory
= serviceProvider
.GetService
<ILoggerFactory
>();
73 if (loggerFactory
!= null)
75 logger
= loggerFactory
.Create(typeof(EmailTemplateService
));
78 viewEngineManager
= serviceProvider
.ViewEngineManager
;
84 /// Creates an instance of <see cref="Message"/>
85 /// using the specified template for the body
87 /// <param name="templateName">Name of the template to load.
88 /// Will look in <c>Views/mail</c> for that template file.</param>
89 /// <param name="layoutName">Name of the layout.</param>
90 /// <param name="parameters">Dictionary with parameters
91 /// that you can use on the email template</param>
92 /// <returns>An instance of <see cref="Message"/></returns>
93 public Message
RenderMailMessage(string templateName
, string layoutName
, object parameters
)
95 return RenderMailMessage(templateName
, layoutName
, new ReflectionBasedDictionaryAdapter(parameters
));
99 /// Creates an instance of <see cref="Message"/>
100 /// using the specified template for the body
102 /// <param name="templateName">Name of the template to load.
103 /// Will look in <c>Views/mail</c> for that template file.</param>
104 /// <param name="layoutName">Name of the layout.</param>
105 /// <param name="parameters">Dictionary with parameters
106 /// that you can use on the email template</param>
107 /// <returns>An instance of <see cref="Message"/></returns>
108 public Message
RenderMailMessage(string templateName
, string layoutName
, IDictionary parameters
)
110 if (logger
.IsDebugEnabled
)
112 logger
.DebugFormat("Rendering email message. Template name {0}", templateName
);
115 if (!templateName
.StartsWith("/"))
117 templateName
= Path
.Combine(EmailTemplatePath
, templateName
);
120 // use the template engine to generate the body of the message
121 StringWriter writer
= new StringWriter();
123 viewEngineManager
.Process(templateName
, layoutName
, writer
, new StringObjectDictionaryAdapter(parameters
));
125 return CreateMessage(writer
);
129 /// Creates an instance of <see cref="Message"/>
130 /// using the specified template for the body
132 /// <param name="templateName">Name of the template to load.
133 /// Will look in Views/mail for that template file.</param>
134 /// <param name="engineContext">The engine context.</param>
135 /// <param name="controller">Controller instance</param>
136 /// <param name="controllerContext">The controller context.</param>
137 /// <param name="doNotApplyLayout">If <c>true</c>, it will skip the layout</param>
138 /// <returns>An instance of <see cref="Message"/></returns>
139 public Message
RenderMailMessage(string templateName
, IEngineContext engineContext
,
140 IController controller
, IControllerContext controllerContext
, bool doNotApplyLayout
)
142 // use the template engine to generate the body of the message
143 StringWriter writer
= new StringWriter();
145 String
[] oldLayout
= controllerContext
.LayoutNames
;
147 if (doNotApplyLayout
)
149 controllerContext
.LayoutNames
= null;
152 if (!templateName
.StartsWith("/"))
154 templateName
= Path
.Combine(EmailTemplatePath
, templateName
);
157 viewEngineManager
.Process(templateName
, writer
, engineContext
, controller
, controllerContext
);
159 controllerContext
.LayoutNames
= oldLayout
;
161 return CreateMessage(writer
);
164 private Message
CreateMessage(StringWriter writer
)
166 // create a message object
167 Message message
= new Message();
169 StringReader reader
= new StringReader(writer
.ToString());
171 bool isInBody
= false;
172 StringBuilder body
= new StringBuilder();
175 while((line
= reader
.ReadLine()) != null)
177 string header
, value;
178 if (!isInBody
&& IsLineAHeader(line
, out header
, out value))
180 switch(header
.ToLowerInvariant())
192 message
.Subject
= value;
195 message
.From
= value;
198 message
.Headers
[header
] = value;
206 if (line
== string.Empty
)
211 body
.AppendLine(line
);
215 message
.Body
= body
.ToString();
217 if (message
.Body
.ToLowerInvariant().IndexOf("<html>") != -1)
219 message
.Format
= Format
.Html
;
225 private static bool IsLineAHeader(string line
, out string header
, out string value)
227 Match match
= HeaderRegEx
.Match(line
);
231 header
= match
.Groups
["header"].ToString().ToLower();
232 value = match
.Groups
["value"].ToString();
237 header
= value = null;