1' Copyright (c) 2008 Silken Web - Free BSD License
2' All rights reserved.
3'
4' Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5' * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer
6' * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
7' * Neither the name of Silken Web nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
8'
9' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
10' THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
11' BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
12' GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13' LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
14' DAMAGE.
15
16Imports System.Net.Mail
17Imports SilkenWeb.Entities
18Imports System.Text.RegularExpressions
19Imports System.Reflection
20Imports SilkenWeb.Validation
21Imports System.Globalization
22Imports SilkenWeb.Reflection
23
24Namespace SilkenWeb
25
26    ''' <summary>
27    ''' Represents an Email and what you can do with it.
28    ''' </summary>
29    ''' <remarks>
30    ''' Keith Jackson
31    ''' 11/04/2008
32    '''
33    ''' This class is intended to be inherrited for providing all manner of system generated emails, each represented by it's own class.
34    ''' </remarks>
35    Public MustInherit Class EmailBase : Implements IValidatable, IDisposable
36
37#Region " Constants "
38
39        Public Const LenientRegexPattern As String = "\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*"
40        Public Const StrictRegexPattern As String = "^(([^<>()[\]\\.,;:\s@\""]+(\.[^<>()[\]\\.,;:\s@\""]+)*)|(\"".+\""))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$"
41        Public Const InvalidEmailAddressError As String = "The Email address provided was invalid"
42        Public Const InvalidEmailAddressErrorWithAddress As String = "The Email address, {0}, provided was invalid"
43        Public Const NullEmailAddressError As String = "The Email address was not provided"
44
45#End Region
46
47#Region " Fields "
48
49        Private disposedValue As Boolean
50
51        Private _message As MailMessage = New MailMessage()
52        Private _mailClient As SmtpClient
53
54        Private _useStrictValidation As Boolean
55
56#End Region
57
58#Region " Construction "
59
60        ''' <summary>
61        ''' Instantiates a new Email of the derived type.
62        ''' </summary>
63        ''' <param name="sender">The email address of the sender of the message.</param>
64        ''' <param name="recipients">The email addresses of the recipients of the message.</param>
65        ''' <param name="subject">The subject of the message.</param>
66        ''' <param name="body">The body of the message.</param>
67        Protected Sub New(ByVal sender As String, ByVal subject As String, ByVal body As String, ByVal ParamArray recipients As String())
68            _message.From = New MailAddress(sender)
69            For i As Integer = 0 To recipients.Length - 1
70                _message.To.Add(recipients(i))
71            Next
72            _message.Subject = subject
73            _message.Body = body
74        End Sub
75
76#End Region
77
78#Region " Properties "
79
80        ''' <summary>
81        ''' Gets the Attachments for the message.
82        ''' </summary>
83        Protected Overridable ReadOnly Property Attachments() As AttachmentCollection
84            Get
85                Return _message.Attachments
86            End Get
87        End Property
88
89        ''' <summary>
90        ''' The email addresses of the BCC recipients of the message.
91        ''' </summary>
92        Public Property BccRecipients() As String()
93            Get
94                Return _message.Bcc.ToAddressStringArray()
95            End Get
96            Set(ByVal value As String())
97                _message.Bcc.Clear()
98                _message.Bcc.Add(value.ToDelimitedString())
99            End Set
100        End Property
101
102        ''' <summary>
103        ''' The body of the message.
104        ''' </summary>
105        Protected Overridable Property Body() As String
106            Get
107                Return _message.Body
108            End Get
109            Set(ByVal value As String)
110                _message.Body = value
111            End Set
112        End Property
113
114        ''' <summary>
115        ''' The email addresses of the CC recipients of the message.
116        ''' </summary>
117        Public Property CCRecipients() As String()
118            Get
119                Return _message.CC.ToAddressStringArray()
120            End Get
121            Set(ByVal value As String())
122                _message.CC.Clear()
123                _message.CC.Add(value.ToDelimitedString())
124            End Set
125        End Property
126
127        ''' <summary>
128        ''' Gets or Sets a flag to indicate if the body of the message is HTML.
129        ''' </summary>
130        Public Property IsBodyHtml() As Boolean
131            Get
132                Return _message.IsBodyHtml
133            End Get
134            Set(ByVal value As Boolean)
135                _message.IsBodyHtml = value
136            End Set
137        End Property
138
139        ''' <summary>
140        ''' Gets the Mail message wrapped by the EmailBase class.
141        ''' </summary>
142        Protected ReadOnly Property Message() As MailMessage
143            Get
144                Return _message
145            End Get
146        End Property
147
148        ''' <summary>
149        ''' Gets or Sets the Priority of the message.
150        ''' </summary>
151        Public Property Priority() As MailPriority
152            Get
153                Return _message.Priority
154            End Get
155            Set(ByVal value As MailPriority)
156                _message.Priority = value
157            End Set
158        End Property
159
160        ''' <summary>
161        ''' The email addresses of the recipients of the message.
162        ''' </summary>
163        Public Property Recipients() As String()
164            Get
165                Return _message.To.ToAddressStringArray()
166            End Get
167            Set(ByVal value As String())
168                _message.To.Clear()
169                _message.To.Add(value.ToDelimitedString())
170            End Set
171        End Property
172
173        ''' <summary>
174        ''' The reply email address of the sender of the message.
175        ''' </summary>
176        Public Property ReplyTo() As String
177            Get
178                If _message.ReplyTo Is Nothing Then
179                    Return String.Empty
180                Else
181                    Return _message.ReplyTo.Address
182                End If
183            End Get
184            Set(ByVal value As String)
185                If _message.ReplyTo Is Nothing Then
186                    _message.ReplyTo = New MailAddress(value)
187                Else
188                    _message.ReplyTo = New MailAddress(value, _message.ReplyTo.DisplayName)
189                End If
190            End Set
191        End Property
192
193        ''' <summary>
194        ''' The reply display name of the sender of the message.
195        ''' </summary>
196        Public Property ReplyToDisplayName() As String
197            Get
198                If _message.ReplyTo Is Nothing Then
199                    Return String.Empty
200                Else
201                    Return _message.ReplyTo.DisplayName
202                End If
203            End Get
204            Set(ByVal value As String)
205                If _message.ReplyTo Is Nothing Then
206                    _message.ReplyTo = New MailAddress(_message.From.Address, value)
207                Else
208                    _message.ReplyTo = New MailAddress(_message.ReplyTo.Address, value)
209                End If
210            End Set
211        End Property
212
213        ''' <summary>
214        ''' The email address of the sender of the message.
215        ''' </summary>
216        Public Overridable Property Sender() As String
217            Get
218                Return _message.From.Address
219            End Get
220            Protected Set(ByVal value As String)
221                _message.From = New MailAddress(value, _message.From.DisplayName)
222            End Set
223        End Property
224
225        ''' <summary>
226        ''' The display name of the sender of the message.
227        ''' </summary>
228        Public Overridable Property SenderDisplayName() As String
229            Get
230                Return _message.From.DisplayName
231            End Get
232            Protected Set(ByVal value As String)
233                _message.From = New MailAddress(_message.From.Address, value)
234            End Set
235        End Property
236
237        ''' <summary>
238        ''' The subject of the message.
239        ''' </summary>
240        Public Overridable Property Subject() As String
241            Get
242                Return _message.Subject
243            End Get
244            Protected Set(ByVal value As String)
245                _message.Subject = value
246            End Set
247        End Property
248
249#End Region
250
251#Region " Methods "
252
253#Region " Send Methods "
254
255        ''' <summary>
256        ''' Sends this email
257        ''' </summary>
258        ''' <param name="mailServer">The SMTP server to use to send the email.</param>
259        Public Sub Send(ByVal mailServer As String)
260            _mailClient = New SmtpClient(mailServer)
261            _mailClient.Send(_message)
262        End Sub
263
264        ''' <summary>
265        ''' Sends this email asynchronously.
266        ''' </summary>
267        ''' <param name="mailServer">The SMTP server to use to send the email.</param>
268        ''' <param name="userToken">A user defined token passed to the recieving method on completion of the asynchronous task.</param>
269        Public Sub SendAsync(ByVal mailServer As String, ByVal userToken As Object)
270            _mailClient = New SmtpClient(mailServer)
271            _mailClient.SendAsync(_message, userToken)
272        End Sub
273
274        ''' <summary>
275        ''' Cancels an attempt to send this email asynchronously.
276        ''' </summary>
277        Public Sub SendAsyncCancel()
278            _mailClient.SendAsyncCancel()
279        End Sub
280
281#End Region
282
283#End Region
284
285#Region " IValidatable Implementation "
286
287        ''' <summary>
288        ''' gets and Sets a flag to indicate whether to use strict validation.
289        ''' </summary>
290        Public Property UseStrictValidation() As Boolean
291            Get
292                Return _useStrictValidation
293            End Get
294            Set(ByVal value As Boolean)
295                _useStrictValidation = value
296            End Set
297        End Property
298
299        ''' <summary>
300        ''' Validates this email.
301        ''' </summary>
302        ''' <returns>A ValidationResponse, containing a flag to indicate if validation was passed and a collection of Property Names and validation errors.</returns>
303        Public Function Validate() As ValidationResponse Implements IValidatable.Validate
304
305            Dim retVal As New ValidationResponse()
306            Dim mailRegEx As String = If(_useStrictValidation, StrictRegexPattern, LenientRegexPattern)
307
308            ValidateAddress("Sender", retVal, mailRegEx, True)
309            ValidateAddresses("Recipients", retVal, mailRegEx, True)
310            ValidateAddresses("CcRecipients", retVal, mailRegEx)
311            ValidateAddresses("BccRecipients", retVal, mailRegEx)
312            ValidateAddress("ReplyTo", retVal, mailRegEx)
313
314            Return retVal
315
316        End Function
317
318        ''' <summary>
319        ''' Validates a single Email Address property.
320        ''' </summary>
321        ''' <param name="propertyName">The name of the property to validate.</param>
322        ''' <param name="retVal">The validation response object.</param>
323        ''' <param name="mailRegEx">The regular expression pattern to use for validation.</param>
324        Private Overloads Sub ValidateAddress(ByVal propertyName As String, ByRef retVal As ValidationResponse, ByVal mailRegEx As String)
325            ValidateAddress(propertyName, retVal, mailRegEx, False)
326        End Sub
327
328        ''' <summary>
329        ''' Validates a single Email Address property.
330        ''' </summary>
331        ''' <param name="propertyName">The name of the property to validate.</param>
332        ''' <param name="retVal">The validation response object.</param>
333        ''' <param name="mailRegEx">The regular expression pattern to use for validation.</param>
334        ''' <param name="required">Indicates if the address is required; False if not specified.</param>
335        Private Overloads Sub ValidateAddress(ByVal propertyName As String, ByRef retVal As ValidationResponse, ByVal mailRegEx As String, ByVal required As Boolean)
336
337            Dim emailAddress As String = ReflectionHelper.Properties.GetProperty(Of String)(Me, propertyName)
338
339            If emailAddress Is Nothing OrElse emailAddress.Length = 0 Then
340                If required Then retVal.Add(New KeyValuePair(Of String, String)(propertyName, NullEmailAddressError))
341            Else
342                If (Not Regex.IsMatch(emailAddress, mailRegEx)) Then
343                    retVal.Add(New KeyValuePair(Of String, String)(propertyName, InvalidEmailAddressError))
344                End If
345            End If
346
347        End Sub
348
349        ''' <summary>
350        ''' Validates a string array of Email Address property.
351        ''' </summary>
352        ''' <param name="propertyName">The name of the property to validate.</param>
353        ''' <param name="retVal">The validation response object.</param>
354        ''' <param name="mailRegEx">The regular expression pattern to use for validation.</param>
355        Private Overloads Sub ValidateAddresses(ByVal propertyName As String, ByRef retVal As ValidationResponse, ByVal mailRegEx As String)
356            ValidateAddresses(propertyName, retVal, mailRegEx, False)
357        End Sub
358
359        ''' <summary>
360        ''' Validates a string array of Email Address property.
361        ''' </summary>
362        ''' <param name="propertyName">The name of the property to validate.</param>
363        ''' <param name="retVal">The validation response object.</param>
364        ''' <param name="mailRegEx">The regular expression pattern to use for validation.</param>
365        ''' <param name="required">Indicates if the address is required; False if not specified.</param>
366        Private Overloads Sub ValidateAddresses(ByVal propertyName As String, ByRef retVal As ValidationResponse, ByVal mailRegEx As String, ByVal required As Boolean)
367
368            Dim emailAddresses() As String = ReflectionHelper.Properties.GetProperty(Of String())(Me, propertyName)
369
370            If emailAddresses Is Nothing OrElse emailAddresses.Length = 0 Then
371                If required Then retVal.Add(New KeyValuePair(Of String, String)(propertyName, String.Format(CultureInfo.CurrentCulture, NullEmailAddressError)))
372            Else
373                For i As Integer = 0 To emailAddresses.Length - 1
374                    If (Not Regex.IsMatch(emailAddresses(i), mailRegEx)) Then
375                        retVal.Add(New KeyValuePair(Of String, String)(propertyName, String.Format(CultureInfo.CurrentCulture, InvalidEmailAddressErrorWithAddress, emailAddresses(i))))
376                    End If
377                Next
378            End If
379
380        End Sub
381
382#End Region
383
384#Region " IDisposable Implementation "
385
386        Protected Overridable Sub Dispose(ByVal disposing As Boolean)
387            If Not Me.disposedValue Then
388                If disposing Then
389                    _message.Dispose()
390                End If
391                _mailClient = Nothing
392                _message = Nothing
393            End If
394            Me.disposedValue = True
395        End Sub
396
397        Public Sub Dispose() Implements IDisposable.Dispose
398            ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
399            Dispose(True)
400            GC.SuppressFinalize(Me)
401        End Sub
402
403#End Region
404
405    End Class
406
407End Namespace
408