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