Option Strict On Option Explicit On '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' Utilities - Copyright 2011 © by David Ross Goben. '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Imports System.Text, VB = Microsoft.VisualBasic Public Class Utilities '******************************************************************************* ' Function Name : DecodeBase64ToStr ' Purpose : Decode a provided raw email message string that is encoded to Base64. ' : ' Returns : Decoded String ' : ' NOTES : note that the lone vbCrLf at the end of lines is filtered out. '******************************************************************************* Public Shared Function DecodeBase64ToStr(ByVal strData As String) As String Return Encoding.UTF8.GetChars(DecodeBase64ToBytes(strData)) End Function '******************************************************************************* ' Function Name : DecodeBase64ToBytes ' Purpose : Decode a provided raw email message string that is encoded to Base64. ' : ' Returns : Decoded binary Byte Array ' : ' NOTES : note that the lone vbCrLf at the end of lines is filtered out. '******************************************************************************* 'this modification returns a Byte Array of the Base64 encoded source data Public Shared Function DecodeBase64ToBytes(ByVal strData As String) As Byte() Return System.Convert.FromBase64String(strData.Replace(vbCrLf, vbNullString)) End Function '========================================================================== '========================================================================== '******************************************************************************* ' Function Name : DecodeQuotedPrintable ' Purpose : Method to clean typical control translations, or all of them. ' : This should be invoked for all data coded Quoted-Printable. ' : ' Returns : Provided a raw message string block, it returns a decoded string. ' : ' NOTES : Typical cleaning involves changing "=0D" to vbCr, "=0A" to vbLf, ' : "=20" to a space, and "=3D" to "=", plus any line wrap ' : terminators at the end of lines to vbNullstring. ' : ' : A StringBuilder object will be used, which will very quickly ' : do a replacement of all control code translations using fewer ' : resources, and what resources that are used will be instantly ' : flushed when the method exits. '******************************************************************************* Public Shared Function DecodeQuotedPrintable(ByVal Message As String, Optional ByVal QuickClean As Boolean = False) As String 'set up StringBuilder object with data stripped of any line continuation tags Dim Msg As New StringBuilder(Message.Replace("=" & vbCrLf, vbNullString)) If QuickClean Then 'perform a quick clean (clean up common basics) Return Msg.Replace("=" & vbCrLf, vbNullString).Replace("=0D", vbCr).Replace("=0A", _ vbLf).Replace("=20", " ").Replace("=3D", "=").ToString Else 'perform total cleaning 'store 2-character hex values that require a leading "0" Dim HxData As String = "X0102030405060708090A0B0C0D0E0F" For Idx As Integer = 1 To &HF 'initially process codes 1-15, which require a leading zero Msg.Replace("=" & Mid(HxData, Idx << 1, 2), Chr(Idx)) 'replace hex data with single character code (SHIFT is faster) Next For idx As Integer = &H10 To &HFF 'process the whole 8-bit extended ASCII gambit Msg.Replace("=" & Hex(idx), Chr(idx)) 'replace hex data with single character code Next Return Msg.ToString 'return result string End If End Function '========================================================================== '========================================================================== '******************************************************************************* ' Function Name : DecodeBinHex ' Purpose : Decode a provided raw email message string that is encoded to BinHex. ' : ' Returns : Decoded String ' : ' NOTES : note that the lone vbCrLf at the end of lines is filtered out. '******************************************************************************* Public Shared Function DecodeBinHex(ByVal StrData As String) As Byte() Dim Src() As Byte = Encoding.UTF8.GetBytes(StrData.Replace(vbCrLf, vbNullString).ToUpper) Dim Result() As Byte 'init output buffer ReDim Result(UBound(Src) \ 2) 'set initial dimension to 1024 bytes (includes offset 0) Dim Index As Integer = 0 'init index for Result() array For Idx As Integer = 0 To UBound(Src) Step 2 'scan the string, 2 hex characters at a time Dim CL As Integer = Src(Idx) - 48 'Convert "0" - "F" to 0-F If CL > 10 Then CL -= 7 Dim CR As Integer = Src(Idx + 1) - 48 'do the same for the right hex digit If CR > 10 Then CR -= 7 If Index > UBound(Result) Then ReDim Preserve Result(Index + 255) 'bump by 256 (allow for Index offset) End If Result(Index) = CByte(CL * 16 + CR) 'stuff byte value Index += 1 'bump index Next ReDim Preserve Result(Index - 1) 'set array to final size Return Result 'return the final result End Function '========================================================================== '========================================================================== '******************************************************************************* ' Function Name : TextNeedsEncoding ' Purpose : Determine if HTML text, Rich Text, or Plain Text requires ' : 8-bit code translation to 7-bit Quoted-Printable tags. ' : ' Returns : Provided a source string, it returns a boolena flag. ' : If the returned value is true, the source contains 8-bit data ' : and will be encoded by server. ' : ' NOTES : If text data contains 8-bit values, the default .NET ' : SMTP processor will force this code to be encoded to Base64, ' : even if only a single byte is 8-bit. ' : ' : To avoid this, the Force7BitHtml() method can be invoked on ' : HTML text to ensure that it is 7-bit encoded so that it can ' : be processed as Quoted-Printable or as 7Bit. The ForceQuotedPrintable() ' : method performs essential conversions for non-HTML text, but this ' : would be best served in Attachments and Alternate Views. '******************************************************************************* Public Shared Function TextNeedsEncoding(ByVal Message As String) As Boolean Dim Byt() As Byte = Encoding.UTF8.GetBytes(Message) 'convert message to byte array For Each B As Byte In Byt If CBool(B And &H80) Then Return True Next Return False End Function '========================================================================== '========================================================================== '******************************************************************************* ' Function Name : Force7BitHtml ' Purpose : Method to convert 8-bit code in an HTML message to 7-bit. ' : ' Returns : Provided a string containing HTML code, it will return a string ' : containing HTML code that does not have any 8-bit data embedded. ' : ' NOTES : If any characters in an HTML text string are 8-bit (values ' : greater than 127), then they are converted into a special ' : 7-bit HTML Entity Number, For Example, code 149 (•) is an 8-bit ' : value that can be changed to HTML "•", which will ensure ' : that it will still be displayed on the HTML page, but the HTML ' : souce code will no longer carry an actual 8-bit value. If such ' : code had not been corrected, the encoding of the data would be ' : forced to change from quoted-printable to Base64, because that ' : would be the only way the email processor could guarantee that ' : the email text was fully intact. '******************************************************************************* Public Shared Function Force7BitHtml(ByVal HtmlSource As String) As String Dim Sb As New StringBuilder 'set up string builder for appending data For Idx As Integer = 1 To Len(HtmlSource) Dim C As Integer = AscW(Mid(HtmlSource, Idx, 1)) 'get a single character from the source Select Case C 'check each character Case Is > &H7F, Is < 0 'if 8-bit or unicode code Sb.Append("&#" & C.ToString & ";") 'convert to 7-bit HTML ecoder Case Else Sb.Append(ChrW(C)) 'else save text regardless End Select Next Return Sb.ToString End Function '========================================================================== '========================================================================== '******************************************************************************* ' Function Name : ForceQuotedPrintable ' Purpose : Force 8-bit code in a text message to 7-bit, without data loss. ' : ' Returns : Provided a source string that contains 8-bit data, the 8-bit ' : data is converted to Hex-Tags, and the returned string is 7-bit. ' : ' NOTES : if any characters in a text string are 8-bit (values greater ' : than 127), then they are converted into special 7-bit tags. ' : For Example, code 149 (•) is an 8-bit value that can be changed ' : to hex "=95", which will ensure that it will still be displayed ' : in the text, but the text data will no longer carry an actual ' : of the data would be forced to change from quoted-printable or 7bit ' : to Base64, because that would be the only way the email processor ' : Base64, because that would be the only way the email processor ' : could guarantee that the email text was fully intact. However, ' : you will have to use the DecodeQuotedPrintable() method to convert ' : it back to its original text form. ' : ' : The Encoded text will begin with "=00". Because unencoded null codes ' : are not permitted in email data, you can use this to instantly ' : determine on the receiving end that this code will need to be ' : processed by DecodeQuotedPrintable() a second time (if initially ' : encoded as Quoted-Printable). A second pass would be required, ' : because if this translated code was afterward encoded as Quoted- ' : Printable, and all the "=xx" byte-translations, would be ' : reinterpreted as "=3Dxx", which DecodeQuotedPrintable() would ' : convert back to "=xx", so passing through a second time would ' : properly convert the additional encoding. Further, by checking the ' : text startiing with "=00", you would know that you would need to ' : double-decode the text. Also, you would want to initially skip this ' : initial tag when passing it the second time to DecodeQuotedPrintable(): ' : ' : Dim Result As String = DecodeQuotedPrintable(Message) 'initially decode Quoted-Printable text ' : If VB.Left(Result, 3) = "=00" Then 'tagged as pre-encoded? ' : Return DecodeQuotedPrintable(Mid(Result, 4)) 'yes, so decode again and return, less initial null byte ' : Else ' : Return Result 'otherwise, return result of decoding ' : End If '******************************************************************************* Public Shared Function ForceQuotedPrintable(ByVal Message As String) As String Dim Byt() As Byte = Encoding.UTF8.GetBytes(Message) 'convert message to byte array Dim Sb As New StringBuilder("=00") 'set up string builder for appending data For Each B As Byte In Byt Select Case B 'check each byte Case Is > &H7F 'if 8-bit code Sb.Append("=" & Hex(B)) 'convert to 7-bit tag Case Else Sb.Append(Chr(B)) 'else save text regardless End Select Next Return Sb.ToString End Function '========================================================================== '========================================================================== '******************************************************************************* ' Function Name : QConvertHTML2Text ' Purpose : Short-Form Convert HTML formatted text to plain text ' : ' Returns : Provided a simple HTML source string, it will return a Plain Text ' : string with HTML code removed. '******************************************************************************* Public Shared Function QConvertHTML2Text(ByVal HTMLText As String) As String Return RegularExpressions.Regex.Replace(HTMLText.Replace(" ", " ").Replace(""", """").Replace("'", _ "'"), "<[^>]*>", "").Replace("<", "<").Replace(">", ">").Replace("&", "&").Replace(";;", ";") End Function '========================================================================== '========================================================================== '******************************************************************************* ' Function Name : ConvertHTML2Text ' Purpose : Convert HTML formatted text to plain text ' : ' Returns : Provided a complex HTML string, it will return a Plain Text string ' : with all HTML codes and formatting removed from it. ' : ' NOTE : Numerous of these conversions will convert the text to 8-bit, ' : though most of these sysmbols will not be encountered in most ' : HTML documents we produce. But regardless of that, if you wish ' : to make this conversion the main body message of an email, you ' : may have to further convert this using ForceQuotedPrintable() ' : to maintain Quoted-Printable encoding and avoid Base64, even ' : though this is typically not an issue. However, some few really ' : primitive email readers, typically those that simply allow you ' : to preview email messages, without fully loading them, will not ' ' know how to support Base64, or will not bother with it, but simply ' : display the raw data. RFC 2045 requires email handlers to support it. '******************************************************************************* Public Shared Function ConvertHTML2Text(ByVal HTMLText As String) As String 'instantiate an initially blank StringBuilder object Dim Sb As New StringBuilder() 'first remove leading whitespace of each line and append the result to the StringBuilder Dim ary() As String = Split(HTMLText, vbCrLf) For Each S As String In ary Sb.Append(S.TrimStart(Chr(9), " "c)) Next 'replace reserved entities (except <, >, and &) Sb.Replace(""", """").Replace("'", "'").Replace(" ", " ") 'replace HTML paragraph, line breaks, and table entry terminators with vbCrLf Sb.Replace("

", vbCrLf).Replace("

", vbCrLf).Replace("

", vbCrLf).Replace("

", vbCrLf).Replace("
", _ vbCrLf).Replace("
", vbCrLf).Replace("", vbCrLf).Replace("", vbCrLf) 'replace ISO 8859-1 Symbols (160-255). Note that any matches will make the text 8-bit Sb.Replace("¡", "¡").Replace("¢", "¢").Replace("£", "£").Replace("¤", _ "¤").Replace("¥", "¥").Replace("¦", "¦").Replace("§", "§").Replace("¨", _ "¨").Replace("©", "©").Replace("ª", "ª").Replace("«", "«").Replace("¬", _ "¬").Replace("­", "-").Replace("®", "®").Replace("¯", "¯").Replace("°", _ "°").Replace("±", "±").Replace("²", "²").Replace("³", "³").Replace("´", _ "´").Replace("µ", "µ").Replace("¶", "¶").Replace("·", "•").Replace("¸", _ "¸").Replace("¹", "¹").Replace("º", "º").Replace("»", "»").Replace("¼", _ "¼").Replace("½", "½").Replace("¾", "¾").Replace("¿", "¿").Replace("×", _ "×").Replace("÷", "÷") 'replace ISO 8859-1 characters. Note that any matches will make the text 8-bit Sb.Replace("À", "À").Replace("Á", "Á").Replace("Â", "Â").Replace("Ã", "Ã").Replace("Ä", _ "Ä").Replace("Å", "Å").Replace("Æ", "Æ").Replace("Ç", "Ç").Replace("È", _ "È").Replace("É", "É").Replace("Ê", "Ê").Replace("Ë", "Ë").Replace("Ì", _ "Ì").Replace("Í", "Í").Replace("Î", "Î").Replace("Ï", "Ï").Replace("Ð", _ "Ð").Replace("Ñ", "Ñ").Replace("Ò", "Ò").Replace("Ó", "Ó").Replace("Ô", _ "Ô").Replace("Õ", "Õ").Replace("Ö", "Ö").Replace("Ø", "Ø").Replace("Ù", _ "Ù").Replace("Ú", "Ú").Replace("Û", "Û").Replace("Ü", "Ü").Replace("Ý", _ "Ý").Replace("Þ", "Þ").Replace("ß", "ß").Replace("à", "à").Replace("á", _ "á").Replace("â", "â").Replace("ã", "ã").Replace("ä", "ä").Replace("å", _ "å").Replace("æ", "æ").Replace("ç", "ç").Replace("è", "è").Replace("é", _ "é").Replace("ê", "ê").Replace("ë", "ë").Replace("ì", "ì").Replace("í", _ "í").Replace("î", "î").Replace("ï", "ï").Replace("ð", "ð").Replace("ñ", _ "ñ").Replace("ò", "ò").Replace("ó", "ó").Replace("ô", "ô").Replace("õ", _ "õ").Replace("ö", "ö").Replace("ø", "ø").Replace("ù", "ù").Replace("ú", _ "ú").Replace("û", "û").Replace("ü", "ü").Replace("ý", "ý").Replace("þ", _ "þ").Replace("ÿ", "ÿ") 'replace Math Symbols Supported by HTML. Note that any matches will make the text 8-bit Sb.Replace("∀", "∀").Replace("∂", "∂").Replace("∃", "∃").Replace("∅", "∅").Replace("∇", _ "∇").Replace("∈", "∈").Replace("∉", "∉").Replace("∋", "∋").Replace("∏", _ "∏").Replace("∑", "∑").Replace("−", "−").Replace("∗", "∗").Replace("√", _ "√").Replace("∝", "∝").Replace("∞", "∞").Replace("∠", "∠").Replace("∧", _ "∧").Replace("∨", "∨").Replace("∩", "∩").Replace("∪", "∪").Replace("∫", _ "∫").Replace("∴", "∴").Replace("∼", "∼").Replace("≅", "≅").Replace("≈", _ "≈").Replace("≠", "≠").Replace("≡", "≡").Replace("≤", "≤").Replace("≥", _ "≥").Replace("⊂", "⊂").Replace("⊃", "⊃").Replace("⊄", "⊄").Replace("⊆", _ "⊆").Replace("⊇", "⊇").Replace("⊕", "⊕").Replace("⊗", "⊗").Replace("⊥", _ "⊥").Replace("⋅", "⋅") 'replace Greek Letters Supported by HTML. Note that any matches will make the text 8-bit Sb.Replace("Α", "Α").Replace("Β", "Β").Replace("Γ", "Γ").Replace("Δ", "Δ").Replace("Ε", _ "Ε").Replace("Ζ", "Ζ").Replace("Η", "Η").Replace("Θ", "Θ").Replace("Ι", _ "Ι").Replace("Κ", "Κ").Replace("Λ", "Λ").Replace("Μ", "Μ").Replace("Ν", _ "Ν").Replace("Ξ", "Ξ").Replace("Ο", "Ο").Replace("Π", "Π").Replace("Ρ", _ "Ρ").Replace("Σ", "Σ").Replace("Τ", "Τ").Replace("Υ", "Υ").Replace("Φ", _ "Φ").Replace("Χ", "Χ").Replace("Ψ", "Ψ").Replace("Ω", "Ω").Replace("α", _ "α").Replace("β", "β").Replace("γ", "γ").Replace("δ", "δ").Replace("ε", _ "ε").Replace("ζ", "ζ").Replace("η", "η").Replace("θ", "θ").Replace("ι", _ "ι").Replace("κ", "κ").Replace("λ", "λ").Replace("μ", "μ").Replace("ν", _ "ν").Replace("ξ", "ξ").Replace("ο", "ο").Replace("π", "π").Replace("ρ", _ "ρ").Replace("ς", "ς").Replace("σ", "σ").Replace("τ", "τ").Replace("υ", _ "υ").Replace("φ", "φ").Replace("χ", "χ").Replace("ψ", "ψ").Replace("ω", _ "ω").Replace("ϑ", "ϑ").Replace("ϒ", "ϒ").Replace("ϖ", "ϖ") 'replace Other Entities Supported by HTML. Note that any matches will make the text 8-bit Sb.Replace("Œ", "Œ").Replace("œ", "œ").Replace("Š", "Š").Replace("š", "š").Replace("Ÿ", _ "Ÿ").Replace("ƒ", "ƒ").Replace("ˆ", "ˆ").Replace("˜", "˜").Replace(" ", _ " ").Replace(" ", " ").Replace(" ", " ").Replace("–", "–").Replace("—", _ "—").Replace("‘", "‘").Replace("’", "’").Replace("‚", "‚").Replace("“", _ " ").Replace("”", " ").Replace("„", "„").Replace("†", "†").Replace("‡", _ "‡").Replace("•", "•").Replace("…", "…").Replace("‰", "‰").Replace("′", _ "′").Replace("″", "″").Replace("‹", "‹").Replace("›", "›").Replace("‾", _ "‾").Replace("€", "€").Replace("™", "™").Replace("←", "←").Replace("↑", _ "↑").Replace("→", "→").Replace("↓", "↓").Replace("↔", "↔").Replace("↵", _ "↵").Replace("⌈", "⌈").Replace("⌉", "⌉").Replace("⌊", "⌊").Replace("⌋", _ "⌋").Replace("◊", "◊").Replace("♠", "♠").Replace("♣", "♣").Replace("♥", _ "♥").Replace("♦", "♦") 'replace special ASCII coding entities that were not captured by the above. Note that values > 127 will make the text 8-bit For Idx As Integer = 1 To 255 'See www.w3schools.com/tags/ref_entities.asp Sb.Replace("&#" & Idx.ToString & ";", Chr(Idx)) 'replace most common numeric entities Next 'Ensure header definitions are followed by vbCrLf Dim NewText As String = RegularExpressions.Regex.Replace(Sb.ToString(), "]*>", vbCrLf) 'Also seek out other Unicode encoded number entities not covered by the above and individually update them Dim Idy As Integer = InStr(NewText, "&#") 'check for a numeric entity Do While Idy <> 0 'loop as long as we find one Dim Idz As Integer = InStr(Idy, NewText, ";") 'find terminating semicolon Dim S As String = Mid(NewText, Idy, Idz - Idy + 1) 'grab expression RegularExpressions.Regex.Replace(NewText, S, Chr(CInt(Mid(S, 3, Len(S) - 3)))) 'replace expression InStr(Idy + 1, NewText, "&#") Loop 'strip remaining HTML text tags, replace < and > placeholders, convert ampersand, replace ;; with ;, then return result Return RegularExpressions.Regex.Replace(NewText, "<[^>]*>", "").Replace("<", _ "<").Replace(">", ">").Replace("&", "&").Replace(";;", ";") End Function '========================================================================== '========================================================================== '******************************************************************************* ' Enum MediaTypes: Structure used by GetMediaType '******************************************************************************* Public Enum MediaTypes As Integer ApplicationOctet ' 0 = Integer Value ApplicationPdf ' 1 ApplicationRtf ' 2 ApplicationSoap ' 3 ApplicationZip ' 4 ImageGif ' 5 ImageJpeg ' 6 ImageTiff ' 7 TextHtml ' 8 TextPlain ' 9 TextRich '10 TextXml '11 End Enum '******************************************************************************* ' Function Name : GetMediaType ' Purpose : Provide easy access to System.Net.Mime.MediaTypes text ' : ' Returns : provided a MediaTypes enumeration value, a string representing ' : the selected type will be returned. '******************************************************************************* Public Shared Function GetMediaType(ByVal MediaType As MediaTypes) As String Select Case MediaType Case MediaTypes.ApplicationPdf Return "application/pdf" Case MediaTypes.ApplicationRtf Return "application/rtf" Case MediaTypes.ApplicationSoap Return "application/soap+xml" Case MediaTypes.ApplicationZip Return "application/zip" Case MediaTypes.ImageGif Return "image/gif" Case MediaTypes.ImageJpeg Return "image/jpeg" Case MediaTypes.ImageTiff Return "image/tiff" Case MediaTypes.TextHtml Return "text/html" Case MediaTypes.TextPlain Return "text/plain" Case MediaTypes.TextRich Return "text/richtext" Case MediaTypes.TextXml Return "text/xml" Case Else Return "application/octet-stream" End Select End Function '========================================================================== '========================================================================== '******************************************************************************* ' Enum TransferEncodings: Structure used by GetTransferEncoding '******************************************************************************* Public Enum TransferEncodings As Integer QuotedPrintable ' 0 = Integer value Base64 ' 1 SevenBit ' 2 End Enum '******************************************************************************* ' Function Name : GetTransferEncoding ' Purpose : Provide easy access to System.Net.Mime.TransferEncoding data ' : ' Returns : Provided a TransferEncodings value, a TransferEncoding value ' : is returned. '******************************************************************************* Public Shared Function GetTransferEncoding(ByVal TransferEncoding As TransferEncodings) As System.Net.Mime.TransferEncoding Return DirectCast(TransferEncoding, System.Net.Mime.TransferEncoding) End Function '========================================================================== '========================================================================== '******************************************************************************* ' Function Name : GetEmailInfo ' Purpose : Break email down into its component parts. ' : ' Returns : EmailInfo object with component parts of email broken down. ' : ' NOTES : This method uses classes EmailItems and EmailInfo. ' : The Message Body, and each AlternnateView or Attachment are ' : contained within EmailItem objects within the EmailIngo object. ' : ' : An EmailItem contains fields for FROM, TO, SUBJECT, Content-Type, ' : a flag indicating if the ContentTypeData is a filename or if it is ' : text formatting, content-transfer-encoding data, and the raw encoded, ' : data, whether it is a message or binary information. If the content- ' : transfer encoding is set to "base64", the data should be decoded ' : using the DecodeBase64() method. If it is "quoted-printable", the ' : data should be decoded using DecodeQuotedPrintable(). If it is ' : "7bit", it is 7-bit data and does not need to be decoded. '******************************************************************************* Public Shared Function GetEmailInfo(ByVal MailMessage As String) As EmailInfo Dim Info As New EmailInfo 'structure to hold breakdown of email Dim Ary() As String = Split(MailMessage, vbCrLf) 'break full email into lines Dim Idx As Integer = 0 'index into Ary() Dim MX As Integer = UBound(Ary) + 1 'find end if list+1 Dim Boundaries As New Collections.Generic.List(Of String) 'boundary definitions Dim IsMultiPart As Boolean = False 'true if we have multiple parts Dim SeekingEncoding As Boolean = False 'true if we are looking for encoding Dim BuildingDataBlock As Boolean = False 'true if we are building a data block Dim HaveMessageBody As Boolean = False 'true if we have the message body defined Dim ContentType As String = vbNullString 'hold last-defined Content Type Dim ContentTypeIsName As Boolean = False 'true of Content Type specified a file Dim ContentTypeData As String = vbNullString 'if block isan attachment Dim ContentEncoding As String = vbNullString 'hold last-defined Content Transfer Encoding Dim ContentBody As String = vbNullString 'block data accumulator '----------------------------------------------------------- Dim Inheader As Integer = 4 'flag for gathering To, From, Date, Subject Do Dim S As String = Ary(Idx) 'grab a line of data from the email ' ' check for important header items ' If CBool(Len(S)) AndAlso CBool(Inheader) Then 'if we are currently in the header... Dim I As Integer = InStr(S, ":") 'find field delimiter If CBool(I) Then 'found one? If VB.Right(S, 1) = ";" Then 'line continues? Idx += 1 'yes, so bump index S &= Ary(Idx).Trim(Chr(9), " "c) 'append next line next line End If Select Case LCase(VB.Left(S, I)) 'yes, check for one of 4 fields Case "from:" 'Found FROM field Info.FromData = Trim(Mid(S, I + 1)) 'stuff to structure Inheader -= 1 'drop 1 from flag Case "to:" 'Found TO field Info.ToData = Trim(Mid(S, I + 1)) 'stuff to structure Inheader -= 1 'drop 1 from flag Case "date:" 'Found DATE field Info.DateData = Trim(Mid(S, I + 1)) 'stuff to structure Inheader -= 1 'drop 1 from flag Case "subject:" 'Found SUBJECT field Info.SubjectData = Trim(Mid(S, I + 1)) 'stuff to structure Inheader -= 1 'drop 1 from flag End Select End If If Not CBool(Inheader) Then 'if InHeader flag is zero SeekingEncoding = True 'start looking for a Content-Transfer-Encoding field S = vbNullString 'purge current data End If End If '------------------------------------------------------- ' check for boundaries '------------------------------------------------------- If CBool(Len(S)) AndAlso CBool(Boundaries.Count) Then 'check any defined boundaries For Idy As Integer = 0 To Boundaries.Count - 1 If CBool(InStr(S, Boundaries.Item(Idy), CompareMethod.Text)) Then If BuildingDataBlock Then Dim Itm As New EmailItem 'create a new item Itm.ContentType = ContentType 'store content type Itm.ContentTypeData = ContentTypeData 'save filename or character set Itm.ContentTypeDataIsFilename = ContentTypeIsName 'save flag indicating if Attachment Itm.ContentEncoding = ContentEncoding 'store encoding Itm.ContentBody = ContentBody 'store data ContentBody = vbNullString 'reset accumulator If HaveMessageBody Then 'already have a message body? If ContentTypeIsName Then 'if an attachment Info.Attachments.Add(Itm) 'add an attachment Else 'otherwise an alternate view Info.AlternateViews.Add(Itm) End If Else Info.MessageBody = Itm 'else stuff new item to message body HaveMessageBody = True 'indicate we now have a message body End If ContentTypeData = vbNullString 'reset filename/charset BuildingDataBlock = False 'turn off building flag End If SeekingEncoding = True 'turn block seeing on again S = vbNullString 'purge current data Exit For End If Next End If '------------------------------------------------------- ' build data block '------------------------------------------------------- If BuildingDataBlock Then ContentBody &= S & vbCrLf 'add a line to content data End If '------------------------------------------------------- ' if seeking encoding '------------------------------------------------------- If CBool(Len(S)) AndAlso SeekingEncoding Then 'are we seeking TCE? Dim I As Integer = InStr(S, ":") 'yes, check for field delimiter If CBool(I) Then 'did we find one? Select Case LCase(VB.Left(S, I)) 'yes, check for types '======================================================= Case "content-type:" 'Content type? ContentType = Mid(S, I + 1).Trim(Chr(9), " "c) 'yes, so grab data If VB.Right(S, 1) = ";" Then 'more to add? Idx += 1 'yes, so bump index ContentType &= Ary(Idx).Trim(Chr(9), " "c) 'grab next line End If ContentTypeIsName = False 'init flag specifying a file as false Dim sbAry() As String = Split(ContentType, ";") 'now check the content type data ContentType = sbAry(0) 'keep first part for ContentType If StrComp(VB.Left(sbAry(0), 10), "multipart/", CompareMethod.Text) = 0 Then 'multipart, so grab second parameter (boundary definition), and strip any quotes Dim Bnd As String = Trim(Mid(sbAry(1), InStr(sbAry(1), "=") + 1)).Replace("""", vbNullString) Boundaries.Add(Bnd) 'and add a boundary ElseIf StrComp(VB.Left(sbAry(1), 5), "name=", CompareMethod.Text) = 0 Then ContentTypeIsName = True 'attachment if a filename specified (otherwise a view) sbAry = Split(sbAry(1), "=") 'multipart, so grab second parameter 'get second part of second parameter (filename definition) ContentTypeData = sbAry(1).Trim().Replace("""", vbNullString) 'strip any quotes Else ContentTypeData = sbAry(1) 'AlternateView, so stuff display character set End If '=================================================== Case "content-transfer-encoding:" ContentEncoding = Mid(S, I + 1).Trim(Chr(9), " "c) 'yes, so grab data SeekingEncoding = False 'turn off seeking flag BuildingDataBlock = True 'turn on building data block flag Idx += 1 'bump to skip required following blank line End Select End If End If Idx += 1 'bump array index Loop While Idx < MX '----------------------------------------------------------- Return Info 'return with filled data block End Function End Class '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ '******************************************************************************* ' Class Name : EmailItem (used by EmailInfo class) ' Purpose : Stores structure of an email block '******************************************************************************* Public Class EmailItem Public ContentType As String = vbNullString 'CONTENT-TYPE data Public ContentTypeData As String = vbNullString 'filename or text encoding Public ContentTypeDataIsFilename As Boolean = False 'True if ContentTypeData specifies a filename Public ContentEncoding As String = vbNullString 'CONTENT-TRANSFER-ENCODING data Public ContentBody As String = vbNullString 'raw data of block End Class '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ '******************************************************************************* ' Class Name : EmailInfo (used by GetEmailInfo method) ' Purpose : Store component parts of an Email '******************************************************************************* Public Class EmailInfo Public FromData As String = vbNullString 'FROM: Public ToData As String = vbNullString 'TO: Public DateData As String = vbNullString 'DATE: Public SubjectData As String = vbNullString 'SUBJECT: Public MessageBody As EmailItem 'contents of message body Public AlternateViews As New Collections.Generic.List(Of EmailItem) 'list of alternate views Public Attachments As New Collections.Generic.List(Of EmailItem) 'list of attachments End Class