add DotNetOpenMail source

This commit is contained in:
UbitUmarov
2018-11-27 14:22:36 +00:00
parent 42b50684d0
commit a32acbdd23
186 changed files with 23323 additions and 0 deletions
@@ -0,0 +1,38 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetOpenMail", "DotNetOpenMail\DotNetOpenMail.csproj", "{6FBB299F-81A1-49EA-B00A-E916F8F797B3}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetOpenMailTests", "DotNetOpenMailTests\DotNetOpenMailTests.csproj", "{74F3DCD7-1325-4968-B466-38618A380CE9}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{6FBB299F-81A1-49EA-B00A-E916F8F797B3}.Debug.ActiveCfg = Debug|.NET
{6FBB299F-81A1-49EA-B00A-E916F8F797B3}.Debug.Build.0 = Debug|.NET
{6FBB299F-81A1-49EA-B00A-E916F8F797B3}.Release.ActiveCfg = Release|.NET
{6FBB299F-81A1-49EA-B00A-E916F8F797B3}.Release.Build.0 = Release|.NET
{74F3DCD7-1325-4968-B466-38618A380CE9}.Debug.ActiveCfg = Debug|.NET
{74F3DCD7-1325-4968-B466-38618A380CE9}.Debug.Build.0 = Debug|.NET
{74F3DCD7-1325-4968-B466-38618A380CE9}.Release.ActiveCfg = Release|.NET
{74F3DCD7-1325-4968-B466-38618A380CE9}.Release.Build.0 = Release|.NET
EndGlobalSection
GlobalSection(SolutionItems) = postSolution
CHANGES.txt = CHANGES.txt
DotNetOpenMailTests.dll.config = DotNetOpenMailTests.dll.config
DotNetOpenMailTests.dll.config.demo = DotNetOpenMailTests.dll.config.demo
DotNetOpenMailTests.dll.log4net = DotNetOpenMailTests.dll.log4net
LICENSE.txt = LICENSE.txt
README.txt = README.txt
README_NUNIT.txt = README_NUNIT.txt
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal
@@ -0,0 +1,354 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.IO;
using System.Text;
using DotNetOpenMail.Encoding;
namespace DotNetOpenMail
{
/// <summary>
/// This is an abstract version of the email attachment. It may or
/// may not contain content, a character encoding method, a
/// mime-encoding method, a content-type designation, a content-id
/// designation, among other things
/// </summary>
public abstract class AbstractEmailAttachment : IEmailStringable
{
internal static readonly String CONTENTTYPE="Content-Type";
internal static readonly String CONTENTTRANSFERENCODING="Content-Transfer-Encoding";
internal static readonly String CONTENTDIPOSITION="Content-Disposition";
internal static readonly String CONTENTID="Content-ID";
internal static readonly String CONTENTDESCRIPTION="Content-Description";
internal static readonly String CHARSET="charset";
/// <summary>
/// The mail encoding type (e.g. quoted-printable, etc)
/// </summary>
protected EncodingType _encodingtype;
/// <summary>
/// The "content type" of the attachment
/// </summary>
protected String _contenttype;
/// <summary>
/// The content-transfer encoding of the attachment
/// </summary>
protected String _contenttransferencoding;
/// <summary>
/// The content disposition of the attachment
/// </summary>
protected String _contentdisposition;
/// <summary>
/// The content description of the attachment
/// </summary>
protected String _contentdescription;
/// <summary>
/// The character set of the encoded text
/// </summary>
protected System.Text.Encoding _charset=null;
/// <summary>
/// The unencoded contents, as a string (optional)
/// </summary>
protected String _contents=null;
/// <summary>
/// An optional content id
/// </summary>
protected String _contentid=null;
/// <summary>
/// The file name to identify the content.
/// (This can be different from the actual file name,
/// if there was one.)
/// </summary>
protected String _filename=null;
/// <summary>
/// The file source to read from
/// </summary>
protected FileInfo _fileinfo=null;
/// <summary>
/// The binary source of the file
/// </summary>
protected Byte[] _contentbytes=null;
/// <summary>
/// Empty constructor
/// </summary>
public AbstractEmailAttachment()
{
}
#region GetEncodedContents
/// <summary>
/// Get the contents, encoded for shipping via SMTP
/// </summary>
/// <param name="encoder">The encoder to encode the contents</param>
/// <returns>returns the encoded string, ready for SMTP transfer</returns>
internal virtual String GetEncodedContents(IEncoder encoder)
{
StringBuilder sb=new StringBuilder();
System.Text.Encoding charset=null;
if (_charset==null)
{
charset=System.Text.Encoding.UTF8;
}
else
{
charset=this._charset;
}
if (_contents!=null)
{
encoder.Encode(new StringReader(_contents), new StringWriter(sb), charset);
}
else if (_fileinfo!=null)
{
encoder.Encode(_fileinfo.OpenRead(), new StringWriter(sb), charset);
}
else if (_contentbytes!=null)
{
encoder.Encode(new BinaryReader(new MemoryStream(_contentbytes)), new StringWriter(sb));
}
String encodedcontents=sb.ToString();
if (encodedcontents.Length!=0 && encodedcontents[encodedcontents.Length-1]!='\n')
{
return encodedcontents+SmtpProxy.ENDOFLINE+SmtpProxy.ENDOFLINE;
}
else
{
return encodedcontents+SmtpProxy.ENDOFLINE;
}
}
#endregion
#region ToDataString
/// <summary>
/// Return the encoded contents, including mime
/// header.
/// </summary>
/// <returns></returns>
public String ToDataString()
{
IEncoder encoder=EncoderFactory.GetEncoder(Encoding);
StringBuilder sb=new StringBuilder();
sb.Append(GetInternalMimeHeader(encoder));
sb.Append(GetEncodedContents(encoder));
return sb.ToString();
}
#endregion
#region Encoding
/// <summary>
/// The encoding type for this attachment.
/// </summary>
public EncodingType Encoding
{
get {return _encodingtype;}
set {_encodingtype=value;}
}
#endregion
#region ContentType
/// <summary>
/// The "content type" of the attachment
/// </summary>
public String ContentType
{
get {return _contenttype;}
set {_contenttype=value;}
}
#endregion
#region CharSet
/// <summary>
/// The character set of the encoded text
/// </summary>
public System.Text.Encoding CharSet
{
get {return _charset;}
set {_charset=value;}
}
#endregion
#region ContentId
/// <summary>
/// An optional content id that is used to refer to
/// the attachment from elsewhere within a multipart/related
/// email.
/// </summary>
public String ContentId
{
get {return _contentid;}
set {_contentid=value;}
}
#endregion
#region FileName
/// <summary>
/// The file name to attach to the attachment.
/// </summary>
public String FileName
{
get {return _filename;}
set {_filename=value;}
}
#endregion
#region Contents
/// <summary>
/// The unencoded contents, as a string (optional)
/// </summary>
public String Contents
{
get {return _contents;}
set {_contents=value;}
}
#endregion
#region ContentBytes
/// <summary>
/// The raw bytes of the content (if this is the way
/// it was set.)
/// </summary>
public byte[] ContentBytes
{
get {return _contentbytes;}
set {_contentbytes=value;}
}
#endregion
#region GetInternalMimeHeader
/// <summary>
/// Create the internal mime header, as found on the
/// mime-attachment itself.
/// </summary>
/// <param name="encoder"></param>
/// <returns></returns>
protected String GetInternalMimeHeader(IEncoder encoder)
{
return MakeContentType()+
MakeTransferEncoding(encoder)+
MakeContentId()+
MakeContentDisposition()+
MakeContentDescription()+
SmtpProxy.ENDOFLINE;
}
#endregion
#region MakeContentType
private String MakeContentType()
{
StringBuilder sb=new StringBuilder(AbstractEmailAttachment.CONTENTTYPE+": "+ContentType+";"+SmtpProxy.ENDOFLINE);
if (_charset!=null)
{
// changed by Pietrovich to fix
// windows-1251 .NET encoding bug.
// windows-1251 BodyName returns "koi8-r"
// instead of "windows-1251"
// but still encodes string as windows-1251
string bodyName = _charset.BodyName;
//#if (FORCEWIN1251)
if ("koi8-r" == _charset.BodyName && "windows-1251" == _charset.HeaderName)
{
bodyName = _charset.HeaderName;
}
//#endif
sb.Append(" "+AbstractEmailAttachment.CHARSET + "=\"" +
bodyName + "\""+SmtpProxy.ENDOFLINE);
// _charset.BodyName + "\""+SmtpProxy.ENDOFLINE);
}
if (FileName!=null)
{
sb.Append(" name=\""+FileName+"\""+SmtpProxy.ENDOFLINE);
}
return sb.ToString();
}
#endregion
#region MakeTransferEncoding
private String MakeTransferEncoding(IEncoder encoder)
{
return AbstractEmailAttachment.CONTENTTRANSFERENCODING+": "+encoder.ContentTransferEncodingString+SmtpProxy.ENDOFLINE;
}
#endregion
#region MakeContentId
private String MakeContentId()
{
if (ContentId!=null)
{
return AbstractEmailAttachment.CONTENTID+": <" + ContentId + ">" + SmtpProxy.ENDOFLINE;
}
return "";
}
#endregion
#region MakeContentDisposition
private String MakeContentDisposition()
{
if (ContentId!=null)
{
return "";
}
if (ContentType!=null && FileName !=null)
{
return AbstractEmailAttachment.CONTENTDIPOSITION+": attachment;"+SmtpProxy.ENDOFLINE+
" filename=\""+FileName+"\""+SmtpProxy.ENDOFLINE;
}
return "";
}
#endregion
#region MakeContentDescription
private String MakeContentDescription()
{
return "";
}
#endregion
}
}
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System.Reflection;
using System.Runtime.CompilerServices;
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly: AssemblyTitle("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
//
// In order to sign your assembly you must specify a key to use. Refer to the
// Microsoft .NET Framework documentation for more information on assembly signing.
//
// Use the attributes below to control which key is used for signing.
//
// Notes:
// (*) If no key is specified, the assembly is not signed.
// (*) KeyName refers to a key that has been installed in the Crypto Service
// Provider (CSP) on your machine. KeyFile refers to a file which contains
// a key.
// (*) If the KeyFile and the KeyName values are both specified, the
// following processing occurs:
// (1) If the KeyName can be found in the CSP, that key is used.
// (2) If the KeyName does not exist and the KeyFile does exist, the key
// in the KeyFile is installed into the CSP and used.
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
// When specifying the KeyFile, the location of the KeyFile should be
// relative to the project output directory which is
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
// located in the project directory, you would specify the AssemblyKeyFile
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
// documentation for more information on this.
//
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]
@@ -0,0 +1,309 @@
<VisualStudioProject>
<CSHARP
ProjectType = "Local"
ProductVersion = "7.10.3077"
SchemaVersion = "2.0"
ProjectGuid = "{6FBB299F-81A1-49EA-B00A-E916F8F797B3}"
>
<Build>
<Settings
ApplicationIcon = ""
AssemblyKeyContainerName = ""
AssemblyName = "DotNetOpenMail"
AssemblyOriginatorKeyFile = ""
DefaultClientScript = "JScript"
DefaultHTMLPageLayout = "Grid"
DefaultTargetSchema = "IE50"
DelaySign = "false"
OutputType = "Library"
PreBuildEvent = ""
PostBuildEvent = ""
RootNamespace = "DotNetOpenMail"
RunPostBuildEvent = "OnBuildSuccess"
StartupObject = ""
>
<Config
Name = "Debug"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "DEBUG;TRACE"
DocumentationFile = "DotNetOpenMail.xml"
DebugSymbols = "true"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "false"
OutputPath = "bin\Debug\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
<Config
Name = "Release"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "TRACE"
DocumentationFile = "DotNetOpenMail.xml"
DebugSymbols = "false"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "true"
OutputPath = "bin\Release\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
</Settings>
<References>
<Reference
Name = "System"
AssemblyName = "System"
HintPath = "..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.dll"
/>
<Reference
Name = "System.Data"
AssemblyName = "System.Data"
HintPath = "..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Data.dll"
/>
<Reference
Name = "System.XML"
AssemblyName = "System.Xml"
HintPath = "..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.XML.dll"
/>
</References>
</Build>
<Files>
<Include>
<File
RelPath = "AbstractEmailAttachment.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "AssemblyInfo.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "EhloSmtpResponse.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "EmailAddress.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "EmailAddressCollection.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "EmailMessage.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "FileAttachment.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "HtmlAttachment.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "IEmailStringable.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ISendableMessage.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ISmtpProxy.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "MailException.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "MessageHeader.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "MessageHeaderCollection.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "MimeBoundary.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "MimeContainer.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "RawEmailMessage.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "RFC2822Date.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SmtpException.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SmtpProxy.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SmtpResponse.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SmtpResponseCode.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SmtpServer.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "TextAttachment.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Encoding\Base64Encoder.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Encoding\DoNothingEncoder.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Encoding\EightBitEncoder.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Encoding\EncoderFactory.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Encoding\EncodingType.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Encoding\IEncoder.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Encoding\QPEncoder.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Encoding\SevenBitEncoder.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Logging\Logger.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Logging\LogMessage.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Resources\ARM.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Resources\DotNetOpenMail.resx"
BuildAction = "EmbeddedResource"
/>
<File
RelPath = "SmtpAuth\ISmtpAuthToken.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SmtpAuth\LoginAuthToken.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SmtpAuth\SmtpAuthFactory.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SmtpAuth\SmtpAuthToken.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Utils\BinaryStreamUtil.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Utils\Configuration.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Utils\EmailAddressParser.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Utils\VersionInfo.cs"
SubType = "Code"
BuildAction = "Compile"
/>
</Include>
</Files>
</CSHARP>
</VisualStudioProject>
@@ -0,0 +1,48 @@
<VisualStudioProject>
<CSHARP LastOpenVersion = "7.10.3077" >
<Build>
<Settings ReferencePath = "C:\Visual Studio Projects\DotNetOpenMail\lib\" >
<Config
Name = "Debug"
EnableASPDebugging = "false"
EnableASPXDebugging = "false"
EnableUnmanagedDebugging = "false"
EnableSQLServerDebugging = "false"
RemoteDebugEnabled = "false"
RemoteDebugMachine = ""
StartAction = "Project"
StartArguments = ""
StartPage = ""
StartProgram = ""
StartURL = ""
StartWorkingDirectory = ""
StartWithIE = "true"
/>
<Config
Name = "Release"
EnableASPDebugging = "false"
EnableASPXDebugging = "false"
EnableUnmanagedDebugging = "false"
EnableSQLServerDebugging = "false"
RemoteDebugEnabled = "false"
RemoteDebugMachine = ""
StartAction = "Project"
StartArguments = ""
StartPage = ""
StartProgram = ""
StartURL = ""
StartWorkingDirectory = ""
StartWithIE = "true"
/>
</Settings>
</Build>
<OtherProjectSettings
CopyProjectDestinationFolder = ""
CopyProjectUncPath = ""
CopyProjectOption = "0"
ProjectView = "ShowAllFiles"
ProjectTrust = "0"
/>
</CSHARP>
</VisualStudioProject>
@@ -0,0 +1,80 @@
using System;
using System.Collections;
using DotNetOpenMail.SmtpAuth;
namespace DotNetOpenMail
{
/// <summary>
/// The server response from EHLO
/// </summary>
public class EhloSmtpResponse
{
private int _responseCode=0;
private String _message;
ArrayList smtpAuthTypes=new ArrayList();
/// <summary>
/// Create an instance of the EhloSmtpResponse class
/// </summary>
public EhloSmtpResponse()
{
}
/// <summary>
/// Get the available Auth Types strings
/// as reported by the server.
/// (e.g. "login", etc.)
/// </summary>
/// <returns></returns>
public String[] GetAvailableAuthTypes()
{
String[] stringArray=new String[smtpAuthTypes.Count];
smtpAuthTypes.CopyTo(stringArray);
return stringArray;
//return (SmtpAuthType[]) smtpAuthTypes.ToArray(typeof (SmtpAuthType[]));
}
/// <summary>
/// Add an Auth type (by string as contained in the
/// EHLO authentication. These are converted to lower
/// case.
/// </summary>
/// <param name="authType">The auth type from EHLO</param>
public void AddAvailableAuthType(String authType)
{
smtpAuthTypes.Add(authType.Trim().ToLower());
}
/*
/// <summary>
/// Add an Auth type
/// </summary>
/// <param name="smtpAuthType"></param>
public void AddAvailableAuthType(SmtpAuthType smtpAuthType)
{
smtpAuthTypes.Add(smtpAuthType);
}
*/
/// <summary>
/// The SMTP Reponse code
/// </summary>
public int ResponseCode
{
get { return _responseCode; }
set { _responseCode=value; }
}
/// <summary>
/// The SMTP Message. This will be "OK" if successful,
/// otherwise it will be the part that failed.
/// </summary>
public String Message
{
get { return _message; }
set { _message=value; }
}
}
}
@@ -0,0 +1,205 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using DotNetOpenMail.Encoding;
namespace DotNetOpenMail
{
/// <summary>
/// An email address.
/// The two parts of the email address object
/// are the email address itself and the
/// name. The name may be encoded if desired.
/// </summary>
public class EmailAddress : IEmailStringable
{
private String _email=null;
private String _name=null;
private System.Text.Encoding _charset;
private Encoding.EncodingType _encodingtype=Encoding.EncodingType.QuotedPrintable;
#region EmailAddress
/// <summary>
/// Create an instance of an email address object.
/// </summary>
/// <param name="email">The address portion of the email</param>
/// <param name="name">The name portion of the email.</param>
public EmailAddress(String email, String name)
{
if (email!=null)
{
email=email.Trim();
}
this._email=email;
this._name=name;
}
#endregion
#region EmailAddress
/// <summary>
/// Create an instance of an email address object.
/// </summary>
/// <param name="email">The address portion of the email</param>
public EmailAddress(String email)
{
if (email!=null)
{
email=email.Trim();
}
else
{
email="";
}
this._email=email;
}
#endregion
#region EmailAddress
/// <summary>
/// Create an character-encoded instance of an email address object.
/// </summary>
/// <param name="email">The address portion of the email</param>
/// <param name="name">The name portion of the email.</param>
/// <param name="charset">The character set to encode the name portion of the email address.</param>
/// <param name="encodingtype">The encoding type to use to encode the name portion of the mail address.</param>
public EmailAddress(String email, String name, Encoding.EncodingType encodingtype, System.Text.Encoding charset)
{
if (email!=null)
{
email=email.Trim();
}
this._email=email;
this._name=name;
this._charset=charset;
this._encodingtype=encodingtype;
}
#endregion
#region Email
/// <summary>
/// The email address portion of the email address object
/// </summary>
public String Email
{
get {return _email;}
}
#endregion
#region Name
/// <summary>
/// The name portion of the email address object
/// </summary>
public String Name
{
get {return _name;}
}
#endregion
#region QuoteSpecials
private String QuoteSpecials(String str)
{
StringBuilder sb=new StringBuilder();
bool needsQuotes=false;
for (int i=0; i< str.Length; i++)
{
char ch=str[i];
if (ch=='\"')
{
needsQuotes=true;
sb.Append('\\');
}
else if (ch=='(' || ch==')' ||
ch=='<' || ch=='>' ||
ch==']' || ch=='[' ||
ch==':' || ch==';' ||
ch=='@' || ch=='\\' ||
ch==',' || ch=='.')
{
needsQuotes=true;
}
sb.Append(ch);
}
if (needsQuotes)
{
return "\""+sb.ToString()+"\"";
}
else
{
return sb.ToString();
}
}
#endregion
#region ToDataString
/// <summary>
/// Create the string representation of this email address
/// (encoded or otherwise) as it will appear in the email
/// </summary>
/// <returns></returns>
public String ToDataString()
{
if (_name!=null && _name.Trim()!="")
{
IEncoder encoder=Encoding.EncoderFactory.GetEncoder(_encodingtype);
System.Text.Encoding thecharset=_charset;
if (thecharset==null)
{
thecharset=Utils.Configuration.GetInstance().GetDefaultCharset();
}
String encodedname=encoder.EncodeHeaderString("", QuoteSpecials(Name.Trim()), thecharset, false);
return encodedname+" <"+Email+">";
}
else
{
return "<"+Email+">";
}
}
#endregion
#region ToString
/// <summary>
/// Calls ToDataString.
/// </summary>
/// <returns></returns>
public override String ToString()
{
return ToDataString();
}
#endregion
}
}
@@ -0,0 +1,151 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.Collections;
using DotNetOpenMail.Encoding;
namespace DotNetOpenMail
{
/// <summary>
/// A collection of EmailAddress objects. Implements
/// CollectionBase
/// </summary>
public class EmailAddressCollection : CollectionBase
{
/// <summary>
/// Create a new instance of the EmailAddressCollection
/// </summary>
public EmailAddressCollection()
{
}
#region Add
/// <summary>
/// Add an object to the collection
/// </summary>
/// <param name="emailaddress">The EmailAddress object to add</param>
/// <returns></returns>
public int Add( EmailAddress emailaddress )
{
return( List.Add( emailaddress ) );
}
#endregion
#region Add
/// <summary>
/// Append a collection of objects to the existing collection
/// </summary>
/// <param name="emailaddresses">The EmailAddressCollection to append to the existing collection.</param>
public void AddCollection( EmailAddressCollection emailaddresses )
{
foreach (EmailAddress emailaddress in emailaddresses)
{
List.Add(emailaddress);
}
}
#endregion
#region IndexOf
/// <summary>
/// Find the index of the EmailAddress in the collection
/// </summary>
/// <param name="value">The object to find.</param>
/// <returns>The index, from 0, or -1 if not found.</returns>
public int IndexOf( EmailAddress value )
{
return( List.IndexOf( value ) );
}
#endregion
#region Insert
/// <summary>
/// Insert an EmailAddress into the collection at the
/// specified index.
/// </summary>
/// <param name="index">The index, starting at zero.</param>
/// <param name="emailaddress">The email address to add to the collection</param>
public void Insert( int index, EmailAddress emailaddress )
{
List.Insert( index, emailaddress );
}
#endregion
#region Remove
/// <summary>
/// Remove an address, if found, from the collection.
/// </summary>
/// <param name="emailaddress">The EmailAddress to remove</param>
public void Remove( EmailAddress emailaddress )
{
List.Remove( emailaddress );
}
#endregion
#region ToDataString
/// <summary>
/// Render the email addresses in a comma-separated list,
/// suitable for being rendered in an email.
/// </summary>
/// <returns></returns>
public String ToDataString()
{
StringBuilder sb=new StringBuilder();
bool doneone=false;
foreach (EmailAddress emailaddress in List)
{
if (!doneone)
{
doneone=true;
}
else
{
sb.Append(", ");
}
sb.Append(emailaddress.ToDataString());
}
return sb.ToString();
}
#endregion
#region ToString
/// <summary>
/// Calls ToDataString().
/// </summary>
/// <returns></returns>
public override String ToString()
{
return ToDataString();
}
#endregion
}
}
@@ -0,0 +1,675 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections;
using System.Text;
using DotNetOpenMail.Resources;
using DotNetOpenMail.Utils;
using DotNetOpenMail.Encoding;
//using log4net;
namespace DotNetOpenMail
{
/// <summary>
/// An Email Message
/// </summary>
public class EmailMessage : ISendableMessage
{
#region variables
//private static readonly ILog log = LogManager.GetLogger(typeof(EmailMessage));
private String _subject=null;
private String _organization=null;
private String _bodytext=null;
private EmailAddress _fromaddress=null;
private EmailAddressCollection _toaddresses=new EmailAddressCollection();
private EmailAddressCollection _ccaddresses=new EmailAddressCollection();
private EmailAddressCollection _bccaddresses=new EmailAddressCollection();
private EmailAddress _envelopefromaddress=null;
private String _contenttype;
private MimeBoundary _mimeboundary;
private TextAttachment _textpart=null;
private HtmlAttachment _htmlpart=null;
private String _xmailer=null;
private ArrayList _mixedfileattachments=new ArrayList();
private ArrayList _relatedfileattachments=new ArrayList();
private MessageHeaderCollection _custommessageheaders=new MessageHeaderCollection();
private System.Text.Encoding _charset;
private Encoding.EncodingType _encodingtype=Encoding.EncodingType.QuotedPrintable;
#endregion
#region EmailMessage
/// <summary>
/// Create a new instance of an EmailMessage.
/// </summary>
public EmailMessage()
{
_mimeboundary=new MimeBoundary();
_charset=System.Text.Encoding.GetEncoding(Configuration.GetInstance().GetDefaultEncoding("iso-8859-1"));
_bodytext=GetNoMimeMessage();
}
#endregion
#region Subject
/// <summary>
/// The subject line or subject header of the
/// email.
/// </summary>
public String Subject
{
get {return _subject;}
set {_subject=value;}
}
#endregion
#region FromAddress
/// <summary>
/// The address that appears in the From header. It will
/// also be used as the Envelope From address in the SMTP
/// negotiation, unless it is overridden by the EnvelopeFromAddress
/// setting.
/// </summary>
public EmailAddress FromAddress
{
get {return _fromaddress;}
set {_fromaddress=value;}
}
#endregion
#region EnvelopeFromAddress
/// <summary>
/// Normally the FromAddress is used as the
/// envelope-from address, but it can be
/// overridden here, if it is not null.
/// </summary>
public EmailAddress EnvelopeFromAddress
{
get {return _envelopefromaddress;}
set {_envelopefromaddress=value;}
}
#endregion
#region AddToAddress
/// <summary>
/// Add a To address to the Headers. This will also
/// be used during the "RCPT TO" SMTP negotiation
/// </summary>
/// <param name="emailaddress">Email Address object of the recipient</param>
public void AddToAddress(EmailAddress emailaddress)
{
_toaddresses.Add(emailaddress);
}
/// <summary>
/// Add a To address to the Headers. This will also
/// be used during the "RCPT TO" SMTP negotiation
/// </summary>
/// <param name="email">The plain email address (don't include the name)</param>
public void AddToAddress(String email)
{
_toaddresses.Add(new EmailAddress(email));
}
#endregion
#region ToAddresses
/// <summary>
/// Retrieve the collection of recipients
/// that will appear in the "To" header of the
/// email.
/// </summary>
public EmailAddressCollection ToAddresses
{
get {return _toaddresses;}
}
#endregion
#region AddCcAddress
/// <summary>
/// Add a Cc address to the Headers. This will also
/// be used during the "RCPT TO" SMTP negotiation
/// </summary>
/// <param name="emailaddress">Email Address object of the recipient</param>
public void AddCcAddress(EmailAddress emailaddress)
{
_ccaddresses.Add(emailaddress);
}
/// <summary>
/// Add a Cc address to the Headers. This will also
/// be used during the "RCPT TO" SMTP negotiation
/// </summary>
/// <param name="email">The plain email address (don't include the name)</param>
public void AddCcAddress(String email)
{
_ccaddresses.Add(new EmailAddress(email));
}
#endregion
#region CcAddresses
/// <summary>
/// Retrieve the collection of recipients
/// that will appear in the "Cc" header of the
/// email.
/// </summary>
public EmailAddressCollection CcAddresses
{
get {return _ccaddresses;}
}
#endregion
#region AddBccAddress
/// <summary>
/// Add a recipient who will be "Blind Carbon Copied"
/// as a recipient of the email. BCC addresses are
/// not added to the email headers, but only appear
/// during the "RCPT TO" SMTP negotiation.
/// </summary>
/// <param name="emailaddress">The EmailAddress object</param>
public void AddBccAddress(EmailAddress emailaddress)
{
_bccaddresses.Add(emailaddress);
}
/// <summary>
/// Add a recipient who will be "Blind Carbon Copied"
/// as a recipient of the email. BCC addresses are
/// not added to the email headers, but only appear
/// during the "RCPT TO" SMTP negotiation.
/// </summary>
/// <param name="email">The plain email address (don't include the name)</param>
public void AddBccAddress(String email)
{
_bccaddresses.Add(new EmailAddress(email));
}
#endregion
#region BccAddresses
/// <summary>
/// Get the current EmailAddressCollection of BCC addresses
/// </summary>
public EmailAddressCollection BccAddresses
{
get {return _bccaddresses;}
}
#endregion
#region Organization
/// <summary>
/// Get/set the organization (as it will appear in the organization
/// header
/// </summary>
public String Organization
{
get {return _organization;}
set {_organization=value;}
}
#endregion
#region XMailer
/// <summary>
/// Get the current XMailer setting for the X-Mailer header.
/// </summary>
public String XMailer
{
get {return this._xmailer;}
set {this._xmailer=value;}
}
#endregion
#region AddCustomHeader
/// <summary>
/// Add a custom mail header, e.g. "X-MyHeader".
/// </summary>
/// <param name="header">The header name (without a colon)</param>
/// <param name="val">The value of the header. This value will not
/// be encoded.</param>
public void AddCustomHeader(String header, String val)
{
_custommessageheaders.Add(new MessageHeader(header, val));
}
#endregion
#region HeaderCharSet
/// <summary>
/// The charset that is used for encoding the headers
/// </summary>
public System.Text.Encoding HeaderCharSet
{
get {return _charset;}
set {_charset=value;}
}
#endregion
#region HeaderEncoding
/// <summary>
/// The mime encoding that is used for encoding the headers
/// </summary>
public Encoding.EncodingType HeaderEncoding
{
get {return this._encodingtype;}
set {_encodingtype=value;}
}
#endregion
#region GetStandardHeaders
/// <summary>
/// Get the minimal header set in the specified character,
/// and using the mime encoder provided.
/// </summary>
private MessageHeaderCollection GetStandardHeaders(System.Text.Encoding charset, IEncoder encoder)
{
MessageHeaderCollection standardheaders=new MessageHeaderCollection();
standardheaders.Add(new MessageHeader("From", _fromaddress.ToDataString()));
standardheaders.Add(new MessageHeader("To", _toaddresses.ToDataString()));
if (_ccaddresses.Count>0)
{
standardheaders.Add(new MessageHeader("Cc", _ccaddresses.ToString()));
}
//if (_bccaddresses.Count>0)
//{
//standardheaders.Add(new MessageHeader("Bcc", _bccaddresses.ToString()));
//}
String subject=_subject;
if (subject==null || subject.Trim()=="")
{
subject=EncodeHeaderValue("Subject", ARM.GetInstance().GetString("no_subject"));
}
standardheaders.Add(new MessageHeader("Subject", EncodeHeaderValue("Subject", subject)));
standardheaders.Add(new MessageHeader("Date", new RFC2822Date(DateTime.Now, TimeZone.CurrentTimeZone).ToString()));
if (!HasBodyTextOnly())
{
standardheaders.Add(new MessageHeader("MIME-Version", "1.0"));
}
#region X-Mailer Header
if (_xmailer!=null)
{
standardheaders.Add(new MessageHeader("X-Mailer", _xmailer));
}
else
{
String xmailer=Configuration.GetInstance().GetXSender();
if (xmailer!=null)
{
standardheaders.Add(new MessageHeader("X-Mailer", xmailer));
}
else
{
standardheaders.Add(new MessageHeader("X-Mailer", "DotNetOpenMail "+VersionInfo.GetInstance().ToString()));
}
}
#endregion
String contentType=null;
if (HasBodyTextOnly())
{
// ignore the mime stuff for now
}
else
{
if (HasMixedContent())
{
contentType="multipart/mixed;"+SmtpProxy.ENDOFLINE+
" boundary=\""+_mimeboundary.BoundaryString+"\"";
}
else if (HasRelatedContent())
{
contentType="multipart/related;"+SmtpProxy.ENDOFLINE+
" boundary=\""+_mimeboundary.BoundaryString+"\"";
}
else
{
contentType="multipart/alternative;"+SmtpProxy.ENDOFLINE+
" boundary=\""+_mimeboundary.BoundaryString+"\"";
}
// note: see http://www.faqs.org/rfcs/rfc2045.html , part 6.4
//contentType+=" charset=\""+charset.BodyName+"\"";
standardheaders.Add(new MessageHeader("Content-Type", contentType));
//standardheaders.Add(new MessageHeader("Content-Transfer-Encoding", encoder.ContentTransferEncodingString));
}
return standardheaders;
}
#endregion
#region EncodeHeaderValue
/// <summary>
/// Encode a header value using the current header encoder and charset.
/// </summary>
/// <param name="name">The header name</param>
/// <param name="val">The header value</param>
/// <returns></returns>
private String EncodeHeaderValue(String name, String val)
{
IEncoder encoder=Encoding.EncoderFactory.GetEncoder(this.HeaderEncoding);
return encoder.EncodeHeaderString(name, val, this.HeaderCharSet, false);
}
#endregion
#region HasMixedContent
/// <summary>
/// Returns true if there is content that should be "multipart/mixed"
/// </summary>
/// <returns>true if the content is multipart/mixed.</returns>
private bool HasMixedContent()
{
return (_mixedfileattachments.Count > 0);
}
#endregion
#region HasRelatedContent
/// <summary>
/// Returns true if there is content that should be "multipart/related"
/// </summary>
/// <returns>true if the content is multipart/related.</returns>
private bool HasRelatedContent()
{
return (_relatedfileattachments.Count > 0);
}
#endregion
#region ToDataStringHeaders
/// <summary>
/// Encode the headers as they will appear in the email
/// </summary>
/// <param name="charset">the charset encoding for the string</param>
/// <param name="encoder">the mime encoding</param>
/// <returns>the encoded string</returns>
internal String ToDataStringHeaders(System.Text.Encoding charset, IEncoder encoder)
{
StringBuilder sb=new StringBuilder();
MessageHeaderCollection standardheaders=GetStandardHeaders(charset, encoder);
sb.Append(standardheaders.ToDataString());
if (_custommessageheaders.Count > 0)
{
sb.Append(_custommessageheaders.ToDataString());
}
return sb.ToString();
}
#endregion
#region HasBodyTextOnly
private bool HasBodyTextOnly()
{
return (_textpart==null
&& _htmlpart==null
&& !HasMixedContent()
&& !HasRelatedContent());
}
#endregion
#region ToDataStringBody
/// <summary>
/// Encode the email body as it will appear in the email
/// </summary>
/// <returns>the encoded body</returns>
internal String ToDataStringBody()
{
bool mixedistop=false;
bool relatedistop=false;
bool alternativeistop=false;
if (HasBodyTextOnly())
{
return FormatBodyText(_bodytext);
}
MimeBoundary relatedcontentmimeboundary=null;
MimeBoundary mixedcontentmimeboundary=null;
MimeBoundary altertnativecontentmimeboundary=null;
#region Determine which uses the top-level boundary
if (HasMixedContent())
{
mixedistop=true;
mixedcontentmimeboundary=_mimeboundary;
relatedcontentmimeboundary=new MimeBoundary();
altertnativecontentmimeboundary=new MimeBoundary();
}
else if (HasRelatedContent())
{
relatedistop=true;
relatedcontentmimeboundary=_mimeboundary;
altertnativecontentmimeboundary=new MimeBoundary();
}
else
{
alternativeistop=true;
altertnativecontentmimeboundary=_mimeboundary;
}
#endregion
MimeContainer alternativemimecontainer=new MimeContainer(altertnativecontentmimeboundary, "multipart/alternative", alternativeistop);
MimeContainer topcontainer=alternativemimecontainer;
#region Text & HTML Parts
if (_textpart!=null)
{
alternativemimecontainer.AddAttachment(_textpart);
}
if (_htmlpart!=null)
{
alternativemimecontainer.AddAttachment(_htmlpart);
}
#endregion
#region Related Content
if (HasRelatedContent())
{
//topcontainer=new MimeContainer(relatedcontentmimeboundary, "multipart/related", relatedistop);
topcontainer=new MimeContainer(relatedcontentmimeboundary, "multipart/related;\r\n type=\"multipart/alternative\"", relatedistop);
topcontainer.AddMimeContainer(alternativemimecontainer);
foreach (FileAttachment attachment in _relatedfileattachments)
{
topcontainer.AddAttachment(attachment);
}
}
#endregion
#region Mixed Content
if (HasMixedContent())
{
MimeContainer oldtopcontainer=topcontainer;
topcontainer=new MimeContainer(mixedcontentmimeboundary, "multipart/mixed", mixedistop);
topcontainer.AddMimeContainer(oldtopcontainer);
foreach (FileAttachment attachment in _mixedfileattachments)
{
topcontainer.AddAttachment(attachment);
}
}
#endregion
if (_bodytext==null)
{
return topcontainer.ToDataString();
}
else
{
return FormatBodyText(_bodytext)+".\r\n\r\n"
+topcontainer.ToDataString();
}
}
#endregion
#region FormatBodyText
/// <summary>
/// format the body text---not implemented yet.
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
private String FormatBodyText(String text)
{
return text;
}
#endregion
#region GetNoMimeMessage
private String GetNoMimeMessage()
{
return ARM.GetInstance().GetString("this_is_mime");
}
#endregion
/// <summary>
/// The text that occurs within the body. By default,
/// it is a MIME notice, but it can be overridden here.
/// NOTE: This is only useful for 7 bit us-ascii currently.
/// </summary>
public String BodyText
{
get { return _bodytext;}
set { _bodytext=value;}
}
#region ToDataString
/// <summary>
/// Render the encoded message for smtp "DATA" transmission.
/// This is the final version that will get sent to the
/// </summary>
/// <returns></returns>
public String ToDataString()
{
IEncoder encoder=EncoderFactory.GetEncoder(HeaderEncoding);
return ToDataStringHeaders(this.HeaderCharSet, encoder)+SmtpProxy.ENDOFLINE+ToDataStringBody();
}
#endregion
#region Send
/// <summary>
/// Send out the email via the smtp server given. If
/// the SMTP server throws an error, an SmtpException will
/// be thrown. All other exceptions will be MailExceptions
/// </summary>
/// <param name="smtpserver">The outgoing SMTP server.</param>
/// <returns>true if sent successfully. (note that this
/// will not currently return false, but in the future
/// a false value may be used)</returns>
public bool Send(SmtpServer smtpserver)
{
//SmtpProxy smtpproxy=smtpserver.GetSmtpProxy();
if(_fromaddress == null)
{
throw new MailException(ARM.GetInstance().GetString("error_no_from"));
}
EmailAddress envelopefrom=_envelopefromaddress;
if (envelopefrom==null)
{
envelopefrom=_fromaddress;
}
EmailAddressCollection allrecipients=new EmailAddressCollection();
allrecipients.AddCollection(_toaddresses);
allrecipients.AddCollection(_ccaddresses);
allrecipients.AddCollection(_bccaddresses);
return smtpserver.Send(this, allrecipients, envelopefrom);
}
#endregion
#region ContentType
/// <summary>
/// Set the content type string in the mime header
/// </summary>
public String ContentType
{
get {return _contenttype;}
set {_contenttype=value;}
}
#endregion
#region TextPart
/// <summary>
/// Set the plain text part of the email. This is optional
/// </summary>
public TextAttachment TextPart
{
set {_textpart=value;}
get {return _textpart;}
}
#endregion
#region HtmlPart
/// <summary>
/// Set the html part of the email. This is optional
/// </summary>
public HtmlAttachment HtmlPart
{
set {_htmlpart=value;}
get {return _htmlpart;}
}
#endregion
#region AddMixedAttachment
/// <summary>
/// Add an attachment which will appear to the user as
/// a separate file. (It is not referred to in the email itself.)
/// </summary>
/// <param name="fileattachment">The file attachment</param>
public void AddMixedAttachment(FileAttachment fileattachment)
{
_mixedfileattachments.Add(fileattachment);
}
#endregion
#region AddRelatedAttachment
/// <summary>
/// Add an image which is referred to from another part of
/// the email (probably the HTML attachment). You should
/// set the ContentID of the file attachment before passing
/// it in.
/// </summary>
/// <param name="fileattachment">The file attachment</param>
public void AddRelatedAttachment(FileAttachment fileattachment)
{
_relatedfileattachments.Add(fileattachment);
}
#endregion
}
}
@@ -0,0 +1,221 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.IO;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// Encode a file in Base64 Encoding.
///
/// See: http://www.freesoft.org/CIE/RFC/1521/7.htm
/// </summary>
public class Base64Encoder : IEncoder
{
/// <summary>
/// The maximum chars per line before end of line char(s)
/// </summary>
public static readonly int MAX_CHARS_PER_LINE=76;
/// <summary>
/// The end-of-line character(s) to use
/// </summary>
public static readonly String END_OF_LINE="\r\n";
#region Base64Encoder
/// <summary>
/// Empty Constructor
/// </summary>
private Base64Encoder()
{
}
#endregion
#region GetInstance
/// <summary>
/// Create an instance of this class
/// </summary>
public static Base64Encoder GetInstance()
{
return new Base64Encoder();
}
#endregion
#region Encode
/// <summary>
/// Encode the Stringreader's data in base64.
///
/// Note: This is not particularly efficient on memory.
/// This method should probably be improved to
/// take advantage of the Reader, rather than
/// taking the whole string into memory.
/// </summary>
/// <param name="stringreader">Reader for incoming string</param>
/// <param name="stringwriter">Writer for outgoing encoded string</param>
/// <param name="encoding">The character encoding for the encoded string.</param>
public void Encode(StringReader stringreader, StringWriter stringwriter, System.Text.Encoding encoding)
{
try
{
String sourceString=stringreader.ReadToEnd();
stringwriter.Write(EncodeString(sourceString, encoding));
}
catch(Exception e)
{
throw new Exception("Error in base64Encode" + e.Message);
}
}
#endregion
#region Encode
/// <summary>
/// Encode the File's data in base64.
/// </summary>
/// <param name="filestream">Reader for incoming string</param>
/// <param name="stringwriter">Writer for outgoing encoded string</param>
/// <param name="charset">The character set for the encoded string</param>
public void Encode(FileStream filestream, StringWriter stringwriter, System.Text.Encoding charset)
{
//fs = finfo.OpenRead();
byte[] buffer = new byte[filestream.Length];
filestream.Read(buffer, 0, buffer.Length);
filestream.Close();
stringwriter.Write(MakeLines(System.Convert.ToBase64String(buffer, 0, buffer.Length)));
//Encode(new StringReader(System.Text.Encoding.ASCII.GetString(buffer)), stringwriter);
}
#endregion
#region Encode
/// <summary>
/// Encode the File's data in base64.
/// </summary>
/// <param name="binaryreader">Reader for incoming string</param>
/// <param name="stringwriter">Writer for outgoing encoded string</param>
public void Encode(BinaryReader binaryreader, StringWriter stringwriter)
{
//fs = finfo.OpenRead();
byte[] b;
int charstoread=Base64Encoder.MAX_CHARS_PER_LINE * 102;
while (true)
{
b = binaryreader.ReadBytes(charstoread);
if (b.Length > 0)
{
stringwriter.Write(MakeLines(Convert.ToBase64String(b)));
}
else
{
break;
}
}
//Encode(new StringReader(System.Text.Encoding.ASCII.GetString(buffer)), stringwriter);
}
#endregion
#region EncodeString
/// <summary>
/// Encode a string in Base64 in a particular characters set
/// </summary>
/// <param name="sourceString">The source text</param>
/// <param name="charset">the charset for the encoded text</param>
/// <returns>Returns an encoded string</returns>
public String EncodeString(String sourceString, System.Text.Encoding charset)
{
byte[] sourceBytes = new byte[sourceString.Length];
sourceBytes = charset.GetBytes(sourceString);
//sourceBytes = System.Text.Encoding.UTF8.GetBytes(sourceString);
String result=Convert.ToBase64String(sourceBytes);
return (MakeLines(result));
}
#endregion
#region EncodeHeaderString
/// <summary>
/// Encode header as per RFC 2047:
/// http://www.faqs.org/rfcs/rfc2047.html
/// </summary>
/// <param name="name">The header name</param>
/// <param name="val">The header text to be encoded (data only)</param>
/// <param name="charset">The charset for the encoded string</param>
/// <param name="forceencoding">ignored for this class</param>
/// <returns>Returns the encoded string</returns>
public String EncodeHeaderString(String name, String val, System.Text.Encoding charset, bool forceencoding)
{
String encodedtext=EncodeString(val, charset);
String tmp="=?"+charset.HeaderName+"?B?"+encodedtext+"?=";
return tmp;
}
#endregion
#region MakeLines
/// <summary>
/// Chop the text into lines that are smaller
/// than MAX_CHARS_PER_LINE
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
private String MakeLines(String source)
{
StringBuilder sb=new StringBuilder();
int pos=0;
for (int i=0; i<source.Length; i++)
{
sb.Append(source[i]);
pos++;
if (pos>=Base64Encoder.MAX_CHARS_PER_LINE)
{
sb.Append(Base64Encoder.END_OF_LINE);
pos=0;
}
}
return sb.ToString();
}
#endregion
#region ContentTransferEncodingString
/// <summary>
/// The String that goes in the content transfer encoding header
/// </summary>
public String ContentTransferEncodingString
{
get {return "base64";}
}
#endregion
}
}
@@ -0,0 +1,96 @@
using System;
using System.Text;
using System.IO;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// An encoder that does nothing. (This is essentially
/// what the 7bit and 8bit encodings are; they are just
/// markers, not actual encodings)
/// </summary>
public abstract class DoNothingEncoder : IEncoder
{
/// <summary>
/// Empty constructor
/// </summary>
public DoNothingEncoder()
{
}
#region Encode
/// <summary>
/// Echo the text back unchanged.
/// </summary>
/// <param name="stringreader">Reader for the incoming string</param>
/// <param name="stringwriter">Writer for the outgoing string</param>
/// <param name="encoding">The encodigng for the outgoing string (ignored)</param>
public void Encode(StringReader stringreader, StringWriter stringwriter, System.Text.Encoding encoding)
{
try
{
stringwriter.Write(stringreader.ReadToEnd());
}
catch(Exception e)
{
throw new Exception("Error writing during Encoding" + e.Message);
}
}
#endregion
#region Encode
/// <summary>
/// Echo the text back unchanged
/// </summary>
/// <param name="filestream">The incoming filestream</param>
/// <param name="stringwriter">The outgoing filestream</param>
/// <param name="charset">Charset (ignored)</param>
public void Encode(FileStream filestream, StringWriter stringwriter, System.Text.Encoding charset)
{
byte[] buffer = new byte[filestream.Length];
filestream.Read(buffer, 0, buffer.Length);
filestream.Close();
stringwriter.Write(buffer);
}
#endregion
#region Encode
/// <summary>
/// Echo the text back unchanged (good for 7bit text only).
/// </summary>
/// <param name="binaryreader">The incoming binaryreader</param>
/// <param name="stringwriter">The outgoing stream</param>
public void Encode(BinaryReader binaryreader, StringWriter stringwriter)
{
throw new Exception("Binary reader doesn't do anything for this reader");
//stringwriter.Write(binaryreader.ReadString());
}
#endregion
/// <summary>
/// Do nothing to the header string
/// </summary>
/// <param name="name">The header key</param>
/// <param name="val">The header value</param>
/// <param name="charset">The charset to encode in (ignored)</param>
/// <param name="forceencoding">(ignored)</param>
/// <returns></returns>
public String EncodeHeaderString(String name, String val, System.Text.Encoding charset, bool forceencoding)
{
return val;
}
#region ContentTransferEncodingString
/// <summary>
/// The String that goes in the content transfer encoding header
/// </summary>
public virtual String ContentTransferEncodingString
{
get {throw new ApplicationException("Implement this");}
}
#endregion
}
}
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.IO;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// Denotes 8bit encoding. Note that this doesn't really
/// encode anything; it just specifies that this email is already
/// in 8-bit encoding.
/// </summary>
public class EightBitEncoder : DoNothingEncoder
{
#region EightBitEncoder
/// <summary>
/// Empty Constructor
/// </summary>
private EightBitEncoder()
{
}
#endregion
#region GetInstance
/// <summary>
/// Create the EightBitEncoder object.
/// </summary>
public static EightBitEncoder GetInstance()
{
return new EightBitEncoder();
}
#endregion
#region ContentTransferEncodingString
/// <summary>
/// The String that goes in the content transfer encoding header
/// </summary>
public override String ContentTransferEncodingString
{
get {return "8bit";}
}
#endregion
}
}
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// Factory for instantiating the right encoder class,
/// given an encoding
/// </summary>
internal class EncoderFactory
{
/// <summary>
/// Empty Constructor.
/// </summary>
internal EncoderFactory()
{
}
/// <summary>
/// Method for determining the correct encoder for this
/// encoding type.
/// </summary>
/// <param name="encodingtype">Enumerated encoding type</param>
/// <returns>Returns the proper IEncoder implementation</returns>
/// <exception cref="ApplicationException">Throws an ApplicationException if the specified encoding is unknown.</exception>
public static IEncoder GetEncoder(EncodingType encodingtype)
{
if (encodingtype==EncodingType.Base64)
{
return Base64Encoder.GetInstance();
}
else if (encodingtype==EncodingType.QuotedPrintable)
{
return QPEncoder.GetInstance();
}
else if (encodingtype==EncodingType.SevenBit)
{
return SevenBitEncoder.GetInstance();
}
else if (encodingtype==EncodingType.EightBit)
{
return EightBitEncoder.GetInstance();
}
else
{
throw new ApplicationException("This encoder type is not implemented");
}
}
}
}
@@ -0,0 +1,27 @@
using System;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// Enumeration of encoding types.
/// </summary>
public enum EncodingType
{
/// <summary>
/// The Quoted-Printable encoding
/// </summary>
QuotedPrintable,
/// <summary>
/// The Base-65 encoding
/// </summary>
Base64,
/// <summary>
/// The 7Bit encoding marker
/// </summary>
SevenBit,
/// <summary>
/// The 8Bit encoding marker
/// </summary>
EightBit
}
}
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.IO;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// An interface for a string encoder
/// </summary>
public interface IEncoder
{
/// <summary>
/// Encode from the stringreader to the stringwriter.
/// </summary>
/// <param name="source">an open stringreader to the source string</param>
/// <param name="destination">where the output is written</param>
/// <param name="charset">the outgoing charset</param>
void Encode(StringReader source, StringWriter destination, System.Text.Encoding charset);
/// <summary>
/// Encode the file stream into the stringwriter.
/// </summary>
/// <param name="filestream">an open stream to file to be read</param>
/// <param name="destination">where the output is written</param>
/// <param name="charset">the outgoing charset</param>
void Encode(FileStream filestream, StringWriter destination, System.Text.Encoding charset);
/// <summary>
/// Encode the binary reader into the stringwriter.
/// </summary>
/// <param name="binaryreader">an open binary reader for the data to be encoded.</param>
/// <param name="destination">where the output is written</param>
void Encode(BinaryReader binaryreader, StringWriter destination);
/// <summary>
/// Encode the string according to rfc-2047 if some of it
/// falls outside the 7bit ASCII charset.
/// </summary>
/// <param name="name">The header key</param>
/// <param name="val">The header value string</param>
/// <param name="charset">Charset for the encoded string</param>
/// <param name="forceencoding">Force encoding, even if in ascii-only.</param>
/// <returns>The encoded string</returns>
String EncodeHeaderString(String name, String val, System.Text.Encoding charset, bool forceencoding);
/// <summary>
/// The String that goes in the content transfer encoding header
/// </summary>
String ContentTransferEncodingString {get;}
}
}
@@ -0,0 +1,446 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.IO;
//using log4net;
using DotNetOpenMail;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// See: http://www.freesoft.org/CIE/RFC/1521/6.htm
/// </summary>
public class QPEncoder : IEncoder
{
/// <summary>
/// Logger
/// </summary>
//private static readonly ILog log = LogManager.GetLogger(typeof(QPEncoder));
/// <summary>
/// Maximum characters per line, before the end-of-line character
/// </summary>
public static readonly int MAX_CHARS_PER_LINE=76;
/// <summary>
/// The end-of-line character(s).
/// </summary>
public static readonly String END_OF_LINE="\r\n";
#region QPEncoder
/// <summary>
/// Empty Constructor
/// </summary>
private QPEncoder()
{
}
#endregion
#region GetInstance
/// <summary>
/// Create an instance of the encoder
/// </summary>
/// <returns>The instantiated Quoted-printable encoder</returns>
public static QPEncoder GetInstance()
{
return new QPEncoder();
}
#endregion
#region Encode
/// <summary>
/// Encode the incoming stream in quoted-printable encoding.
/// </summary>
/// <param name="binaryreader">The incoming binary reader</param>
/// <param name="stringwriter">The outgoing string writer</param>
public void Encode(BinaryReader binaryreader, StringWriter stringwriter)
{
throw new ApplicationException("Not Implemented Yet; use a base64 encoder instead.");
}
#endregion
#region Encode
/// <summary>
/// Encode the incoming stream in quoted-printable encoding.
/// </summary>
/// <param name="filestream">The incoming file stream</param>
/// <param name="stringwriter">The outgoing string writer</param>
/// <param name="charset">The charset to write the outgoing string in</param>
public void Encode(FileStream filestream, StringWriter stringwriter, System.Text.Encoding charset)
{
throw new ApplicationException("Not Implemented Yet; use a base64 encoder instead.");
}
#endregion
#region Encode
/// <summary>
/// Encode the string read by the stringreader into the
/// stringwriter. This implementation does not encode
/// the characters where encoding is optional, and does
/// not encode spaces or tabs (except at the end of a line).
///
/// Line breaks are converted to the RFC line break (CRLF).
// The last linebreak is not included, if any, but this
/// </summary>
/// <param name="stringreader">The incoming string reader</param>
/// <param name="stringwriter">The outgoing stringwriter</param>
/// <param name="charset">The outgoing charset for the string</param>
public void Encode(StringReader stringreader, StringWriter stringwriter, System.Text.Encoding charset)
{
Encode(stringreader, stringwriter, charset, false, 0);
}
#endregion
#region EncodeString
/// <summary>
/// Encode the string in quoted printable format
/// </summary>
/// <param name="str">The source string</param>
/// <param name="charset">The outgoing charset</param>
/// <returns>the encoded string</returns>
public String EncodeString(String str, System.Text.Encoding charset)
{
return EncodeString(str, charset, false, 0);
}
#endregion
#region EncodeString
/// <summary>
/// Encode the string in quoted printable format
/// </summary>
/// <param name="sourceString">The source string</param>
/// <param name="charset">The outgoing charset</param>
/// <param name="forceRFC2047">Force encoding, even if not required by qp RFC</param>
/// <param name="offset">The total characters outside the encoding. This is used to figure
/// out how long the line will be after encoding.</param>
/// <returns>the encoded string</returns>
public String EncodeString(String sourceString, System.Text.Encoding charset, bool forceRFC2047, int offset)
{
StringReader sr=new StringReader(sourceString);
StringBuilder sb=new StringBuilder();
StringWriter sw=new StringWriter(sb);
Encode(sr, sw, charset, forceRFC2047, offset);
return sb.ToString();
}
#endregion
#region EncodeHeaderString
/// <summary>
/// Encode header as per RFC 2047:
/// http://www.faqs.org/rfcs/rfc2047.html
///
/// </summary>
/// <remarks>This doesn't split long lines yet</remarks>
/// <param name="name">the header name</param>
/// <param name="val">the string to encode</param>
/// <param name="charset">The charset to encode to</param>
/// <param name="forceencoding">Force encoding, even if not required by qp RFC</param>
/// <returns>the encoded string, suitable for use in a header</returns>
public String EncodeHeaderString(String name, String val, System.Text.Encoding charset, bool forceencoding)
{
if (forceencoding || IsNonAscii(val))
{
String start="=?"+charset.HeaderName+"?Q?";
String end="?=";
int offset=name.Length+start.Length+end.Length+2; // the 2 is for the colon and space
String encodedtext=EncodeString(val, charset, true, offset);
//log.Debug("LINE BEFORE SPLIT IS "+encodedtext);
if (encodedtext.Length + offset > QPEncoder.MAX_CHARS_PER_LINE)
{
StringBuilder sb=new StringBuilder("");
foreach (String line in encodedtext.Split('\n'))
{
String tmp=line;
if (sb.Length>0)
{
sb.Append(QPEncoder.END_OF_LINE+" ");
}
tmp=line.TrimEnd(new char[] {'\r', '='});
//if (line.LastIndexOf("\r") == line.Length-1)
//{
//tmp=line.Substring(0, line.Length-1);
//}
sb.Append(start+tmp+end);
}
return sb.ToString();
}
else
{
return start+encodedtext+end;
}
}
else
{
return val;
}
}
#endregion
#region EncodeChar
/// <summary>
/// Encode a char according to quoted-printable
/// standard
/// </summary>
/// <param name="ch">the char to encode</param>
/// <returns>the encoded char representation</returns>
private String EncodeChar(char ch)
{
int intch=(int) ch;
if (intch > 255)
{
//log.Debug("encoding qp: "+String.Format("0x{0:X4}", intch));
int ch1=intch >> 8;
int ch2=intch & 0xff;
return String.Format("={0:X2}={1:X2}", ch1, ch2);
}
else
{
return String.Format("={0:X2}",(int) ch);
}
}
#endregion
#region EncodeByte
/// <summary>
/// Encode a byte according to quoted-printable
/// standard
/// </summary>
/// <param name="ch">the byte to encode</param>
/// <returns>the encoded byte representation</returns>
private String EncodeByte(byte ch)
{
return String.Format("={0:X2}",(int) ch);
}
#endregion
#region ContentTransferEncodingString
/// <summary>
/// The String that goes in the content transfer encoding header
/// </summary>
public String ContentTransferEncodingString
{
get {return "quoted-printable";}
}
#endregion
#region NeedsEncoding
/// <summary>
/// Return true if the char needs to be encoded.
/// </summary>
/// <param name="ch"></param>
/// <param name="forceRFC2047"></param>
/// <returns></returns>
internal bool NeedsEncoding(char ch, bool forceRFC2047)
{
if ((ch <= 0x1f && ch != 0x09) || // less than space (except tab)
ch == 0x3d || // equal sign
ch>= 0x7f // above 7bit
|| (forceRFC2047 && (ch==0x20 || ch==0x09 || ch==0x3f))
)
{
return true;
}
else
{
return false;
}
}
#endregion
#region NeedsEncoding
/// <summary>
/// Return true if the byte needs to be encoded.
/// </summary>
/// <param name="ch"></param>
/// <param name="forceRFC2047"></param>
/// <returns></returns>
internal bool NeedsEncoding(byte ch, bool forceRFC2047)
{
if ((ch <= 0x1f && ch != 0x09) || // less than space (except tab)
ch == 0x3d || // equal sign
ch>= 0x7f // above 7bit
|| (forceRFC2047 && (ch==0x20 || ch==0x09 || ch==0x3f))
)
{
return true;
}
else
{
return false;
}
}
#endregion
#region IsNonAscii
/// <summary>
/// Return true if the string needs to be encoded.
/// </summary>
/// <param name="str">The string to check</param>
/// <returns>true if outside 127-bit, or one of the
/// quoted-printable special characters.</returns>
internal bool IsNonAscii(String str)
{
for (int i=0; i<str.Length; i++)
{
if (IsNonAscii(str[i]))
{
return true;
}
}
return false;
}
#endregion
#region IsNonAscii
/// <summary>
/// Check if the character is one of the non-qp
/// characters
/// </summary>
/// <param name="ch">the character to check</param>
/// <returns>true if outside the acceptable qp range</returns>
internal bool IsNonAscii(char ch)
{
if ((ch <= 0x1f && ch != 0x09) || // less than space (except tab)
ch == 0x3d || // equal sign
ch>= 0x7f // above 7bit
)
{
return true;
}
else
{
return false;
}
}
#endregion
#region Encode
/// <summary>
/// Encode the string read by the stringreader into the
/// stringwriter. This implementation does not encode
/// the characters where encoding is optional, and does
/// not encode spaces or tabs (except at the end of a line).
///
/// Line breaks are converted to the RFC line break (CRLF).
// The last linebreak is not included, if any---although this
/// may change in the future.
/// </summary>
/// <param name="stringreader">The incoming string reader</param>
/// <param name="stringwriter">The outgoing stringwriter</param>
/// <param name="charset">The outgoing charset for the string</param>
/// <param name="forceRFC2047">If true, force the encoding of all the
/// <param name="offset">These are the number of characters that
/// will appear outside this string, e.g. the header name, etc.</param>
/// characters (not just those that are given in RFC2027).</param>
public void Encode(StringReader stringreader, StringWriter stringwriter, System.Text.Encoding charset, bool forceRFC2047, int offset)
{
if (offset > QPEncoder.MAX_CHARS_PER_LINE - 15)
{
throw new MailException("Invalid offset (header name is too long): "+offset);
}
String line=null;
bool forceencoding=false;
if (charset==null)
{
charset=Utils.Configuration.GetInstance().GetDefaultCharset();
}
while((line=stringreader.ReadLine())!=null)
{
int columnposition=0;
byte[] bytes=charset.GetBytes(line);
// see Rule #3 (spaces and tabs at end of line are encoded)
StringBuilder blankendchars=new StringBuilder("");
int endpos=bytes.Length-1;
while (endpos >=0 && (bytes[endpos]==0x20 || bytes[endpos]==0x09) )
{
blankendchars.Insert(blankendchars.Length, EncodeByte(bytes[endpos]));
endpos--;
}
for (int i=0; i<=endpos; i++)
{
String towrite="";
if (forceencoding || NeedsEncoding(bytes[i], forceRFC2047))
{
columnposition+=3;
towrite=EncodeByte(bytes[i]);
}
else
{
columnposition+=1;
// this is a single byte, so multibyte chars won't
// be affected by this.
towrite=charset.GetString(new byte[]{bytes[i]});
}
if (offset + columnposition > QPEncoder.MAX_CHARS_PER_LINE )
{
stringwriter.Write("="+QPEncoder.END_OF_LINE);
columnposition=0;
}
stringwriter.Write(towrite);
}
if (blankendchars.Length > 0)
{
if (offset+columnposition+blankendchars.Length > QPEncoder.MAX_CHARS_PER_LINE)
{
stringwriter.Write("="+QPEncoder.END_OF_LINE);
}
stringwriter.Write(blankendchars);
}
if (stringreader.Peek() >= 0)
{
stringwriter.Write("\r\n");
}
}
}
#endregion
}
}
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// Denotes 7bit encoding. Note that this doesn't really
/// encode anything; it just specifies that this email is already
/// in 7-bit ascii encoding.
/// </summary>
public class SevenBitEncoder : DoNothingEncoder
{
/// <summary>
/// Empty constructor
/// </summary>
private SevenBitEncoder()
{
}
/// <summary>
/// Create an instance of this class.
/// </summary>
/// <returns></returns>
public static SevenBitEncoder GetInstance()
{
return new SevenBitEncoder();
}
#region ContentTransferEncodingString
/// <summary>
/// The String that goes in the content transfer encoding header
/// </summary>
public override String ContentTransferEncodingString
{
get {return "7bit";}
}
#endregion
}
}
@@ -0,0 +1,199 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.IO;
//using log4net;
using DotNetOpenMail.Encoding;
namespace DotNetOpenMail
{
/// <summary>
/// A mime representation of a file which can be transferred
/// via email.
/// </summary>
public class FileAttachment : AbstractEmailAttachment
{
//private static readonly ILog log = LogManager.GetLogger(typeof(FileAttachment));
/// <summary>
/// Create a new File attachment from a FileInfo object
/// </summary>
/// <param name="fileinfo">A fileinfo object which points to a local file.</param>
public FileAttachment(FileInfo fileinfo) : this(fileinfo, null)
{
}
/// <summary>
/// Create a new text file attachment from a StreamReader.
/// </summary>
/// <param name="streamreader">An open streamreader</param>
public FileAttachment(StreamReader streamreader) : this(streamreader, null)
{
}
/// <summary>
/// Create a new binary file attachment from a BinaryReader.
/// </summary>
/// <param name="binaryreader">An open binaryreader</param>
public FileAttachment(BinaryReader binaryreader) : this(binaryreader, null)
{
}
/// <summary>
/// Create a new binary file attachment from an array of bytes.
/// </summary>
/// <param name="bytes">An array of bytes</param>
public FileAttachment(byte[] bytes) : this(bytes, null)
{
}
/// <summary>
/// Create a new file attachment from a String.
/// </summary>
/// <param name="content">The contents of the file</param>
public FileAttachment(String content) : this(content, null)
{
}
#region FileAttachment
/// <summary>
/// Create a new File attachment with a contentid from a FileInfo object.
/// The contentid will be used to refer to this attachment in
/// another mime part of the email.
/// </summary>
/// <param name="fileinfo">A fileinfo object which points to a local file.</param>
/// <param name="contentid">the content id value</param>
public FileAttachment(FileInfo fileinfo, String contentid)
{
this.ContentType="binary/octet-stream";
if (FileName==null)
{
FileName=fileinfo.Name;
}
this._fileinfo=fileinfo;
this._contentid=contentid;
this.CharSet=null;
//this.Contents=contents;
this.Encoding=EncodingType.Base64;
//this.Encoder=EncoderFactory.GetEncoder(EncoderFactory.GetEncoder(EncodingType);
}
#endregion
#region FileAttachment
/// <summary>
/// Create a new file attachment from a StreamReader.
/// The contentid will be used to refer to this attachment in
/// another mime part of the email.
/// </summary>
/// <param name="streamreader">An open streamreader</param>
/// <param name="contentid">the content id value</param>
public FileAttachment(StreamReader streamreader, String contentid)
{
if (this.ContentType==null)
{
this.ContentType="binary/octet-stream";
}
String tmp=streamreader.ReadToEnd();
streamreader.Close();
this.Contents=tmp;
this.CharSet=null;
this._contentid=contentid;
this.Encoding=EncodingType.Base64;
}
#endregion
#region FileAttachment
/// <summary>
/// Create a new file attachment from a BinaryReader.
/// The contentid will be used to refer to this attachment in
/// another mime part of the email.
/// </summary>
/// <param name="binaryreader">An open binary readerr</param>
/// <param name="contentid">the content id value</param>
public FileAttachment(BinaryReader binaryreader, String contentid)
{
if (this.ContentType==null)
{
this.ContentType="binary/octet-stream";
}
this._contentbytes=Utils.BinaryReaderUtil.ReadIntoByteArray(binaryreader);
binaryreader.Close();
this.CharSet=null;
this._contentid=contentid;
this.Encoding=EncodingType.Base64;
}
#endregion
#region FileAttachment
/// <summary>
/// Create a new file attachment from a byte array.
/// The contentid will be used to refer to this attachment in
/// another mime part of the email.
/// </summary>
/// <param name="bytes">An array of bytes</param>
/// <param name="contentid">the content id value</param>
public FileAttachment(byte[] bytes, String contentid)
{
if (this.ContentType==null)
{
this.ContentType="binary/octet-stream";
}
this.ContentBytes=bytes;
this.CharSet=null;
this.Encoding=EncodingType.Base64;
}
#endregion
/// <summary>
/// Create a new text file attachment from a String.
/// The contentid will be used to refer to this attachment in
/// another mime part of the email.
/// </summary>
/// <param name="content">The contents of the file</param>
/// <param name="contentid">the content id value</param>
public FileAttachment(String content, String contentid)
{
if (this.ContentType==null)
{
this.ContentType="binary/octet-stream";
}
this.Contents=content;
this.CharSet=null;
this.Encoding=EncodingType.Base64;
this._contentid=contentid;
}
}
}
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using DotNetOpenMail.Encoding;
using DotNetOpenMail.Utils;
namespace DotNetOpenMail
{
/// <summary>
/// An HTML email attachment
/// </summary>
public class HtmlAttachment : AbstractEmailAttachment
{
/// <summary>
/// Create a new HTML Attachment. It flags the content/type
/// as "text/html", uses Quoted Printable encoding by
/// default, and uses the default character set, which is
/// ISO-8859-1 unless otherwise specified in the .config file.
/// </summary>
/// <param name="contents">The HTML content of the attachment</param>
public HtmlAttachment(String contents)
{
this.ContentType="text/html";
this.Contents=contents;
this.CharSet=System.Text.Encoding.GetEncoding(Configuration.GetInstance().GetDefaultEncoding("iso-8859-1"));
this.Encoding=EncodingType.QuotedPrintable;
}
}
}
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail
{
/// <summary>
/// Objects of a class which implements this interface
/// can be converted to a string which can be used in
/// an email.
/// </summary>
internal interface IEmailStringable
{
String ToDataString();
}
}
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail
{
/// <summary>
/// A message which can be sent.
/// </summary>
internal interface ISendableMessage : IEmailStringable
{
bool Send(SmtpServer smtpserver);
}
}
@@ -0,0 +1,95 @@
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
//using log4net;
namespace DotNetOpenMail
{
/// <summary>
/// Interact directly with the SMTP server.
/// </summary>
public interface ISmtpProxy
{
/// <summary>
/// Open the connection
/// </summary>
/// <returns>The SMTP response</returns>
SmtpResponse Open();
/// <summary>
/// Send the HELO command
/// </summary>
/// <param name="localHostName"></param>
/// <returns></returns>
SmtpResponse Helo(String localHostName);
/// <summary>
/// Send the EHLO command
/// </summary>
/// <param name="localHostName"></param>
/// <returns></returns>
EhloSmtpResponse Ehlo(String localHostName);
/// <summary>
/// Send the MAIL FROM command
/// </summary>
/// <param name="mailfrom"></param>
/// <returns></returns>
SmtpResponse MailFrom(EmailAddress mailfrom);
/// <summary>
/// Send one RCPT TO command
/// </summary>
/// <param name="rcptto"></param>
/// <returns></returns>
SmtpResponse RcptTo(EmailAddress rcptto);
/// <summary>
/// Send the DATA command
/// </summary>
/// <returns></returns>
SmtpResponse Data();
/// <summary>
/// Write the message content
/// </summary>
/// <returns></returns>
SmtpResponse WriteData(String str);
/// <summary>
/// Send the QUIT message to the server
/// </summary>
/// <returns></returns>
SmtpResponse Quit();
/// <summary>
/// Close the connection
/// </summary>
/// <returns>The SMTP response</returns>
void Close();
/// <summary>
/// Send the AUTH command
/// </summary>
/// <returns>the SMTP response</returns>
SmtpResponse Auth(String authtype);
/// <summary>
/// Send any old string to the proxy
/// </summary>
/// <returns>the SMTP response</returns>
SmtpResponse SendString(String str);
/// <summary>
/// Turn the SMTP Conversation Capture off/on.
/// If on, GetSmtpConversation will contain the
/// most recent conversation.
/// </summary>
/// <returns>the on/off value</returns>
bool CaptureSmtpConversation {get; set;}
}
}
@@ -0,0 +1,44 @@
using System;
namespace DotNetOpenMail.Logging
{
/// <summary>
/// Summary description for LogMessage.
/// </summary>
public class LogMessage
{
private Object _sender=null;
private String _message=null;
/// <summary>
/// The log message
/// </summary>
public String Message
{
get {return _message;}
set {_message=value;}
}
/// <summary>
/// The sender object
/// </summary>
public Object Sender
{
get {return _sender;}
set {_sender=value;}
}
/// <summary>
/// Log a message
/// </summary>
/// <param name="sender">The object logging the message</param>
/// <param name="message">The message to be logged</param>
public LogMessage(Object sender, String message)
{
this._sender=sender;
this._message=message;
}
}
}
@@ -0,0 +1,77 @@
using System;
namespace DotNetOpenMail.Logging
{
/// <summary>
/// Summary description for Logger.
/// </summary>
public class Logger
{
/// <summary>
/// Log handler delegate
/// </summary>
public delegate void LogHandler(LogMessage logMessage);
/// <summary>
/// Log event
/// </summary>
//public event LogHandler LogEvent;
private static Logger _logger=new Logger();
private Logger()
{
}
/// <summary>
/// Return the singleton object
/// </summary>
/// <returns></returns>
public static Logger GetInstance()
{
return _logger;
}
/// <summary>
/// Log a message with level "Info"
/// </summary>
/// <param name="message"></param>
public void LogInfo(String message)
{
}
/// <summary>
/// Log a message with level "Debug"
/// </summary>
public void LogDebug(String message)
{
}
/// <summary>
/// Log a message with level "Error"
/// </summary>
public void LogError(String message)
{
}
/// <summary>
/// Log the output of sending smtp
/// </summary>
public void LogWriteSMTP(String message)
{
}
/// <summary>
/// Log the reply via smtp
/// </summary>
/// <param name="message"></param>
public void LogReceiveSMTP(String message)
{
}
}
}
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail
{
/// <summary>
/// General Mail Exception, including network errors,
/// connection errors, and configuration errors.
/// </summary>
public class MailException : Exception
{
/// <summary>
/// Create an instance of a MailException
/// </summary>
public MailException() : base()
{
}
/// <summary>
/// Create an instance of a MailException
/// </summary>
/// <param name="message">The message describing the exception</param>
public MailException(string message) : base(message)
{
}
/// <summary>
/// Create an instance of a MailException
/// </summary>
/// <param name="message">The message describing the exception</param>
/// <param name="inner">The inner exception</param>
public MailException(string message, Exception inner) : base(message, inner)
{
}
}
}
@@ -0,0 +1,111 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using DotNetOpenMail.Encoding;
namespace DotNetOpenMail
{
/// <summary>
/// This represents one of the message headers as it
/// appears in the email.
/// </summary>
public class MessageHeader : IEmailStringable
{
private String _name;
private String _value;
private String _encodedvalue=null;
/// <summary>
/// Create a new instance of a MessageHeader
/// </summary>
/// <param name="name">The header name (without a colon)</param>
/// <param name="value">The unencoded value</param>
public MessageHeader(string name, String value)
{
this._name=name;
this._value=value;
}
/// <summary>
/// Create a new instance of a MessageHeader, with a mime-encoded
/// value.
/// </summary>
/// <param name="name">The header name (without a colon)</param>
/// <param name="value">The non-encoded header value</param>
/// <param name="encodedvalue">The mime-encoded value</param>
public MessageHeader(string name, String value, String encodedvalue)
{
this._name=name;
this._value=value;
this._encodedvalue=encodedvalue;
}
/// <summary>
/// The name of the header.
/// </summary>
public String Name
{
get {return this._name;}
}
/// <summary>
/// The unencoded value of the header
/// </summary>
public String Value
{
get {return this._value;}
}
/// <summary>
/// The mime-encoded value of the header
/// </summary>
public String EncodedValue
{
get {return this._encodedvalue;}
}
/// <summary>
/// The string representation of the header, as it will
/// appear in the email.
/// </summary>
/// <returns></returns>
public String ToDataString()
{
if (_encodedvalue!=null)
{
return Name+": "+EncodedValue+SmtpProxy.ENDOFLINE;
}
else
{
return Name+": "+Value+SmtpProxy.ENDOFLINE;
}
}
}
}
@@ -0,0 +1,120 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.IO;
using System.Text;
using System.Collections;
namespace DotNetOpenMail
{
/// <summary>
/// A collection of MessageHeader objects
/// Implements the CollectionBase interface.
/// </summary>
public class MessageHeaderCollection : CollectionBase, IEmailStringable
{
/// <summary>
/// Initializes a new instance of the ArrayList class.
/// </summary>
public MessageHeaderCollection()
{
}
#region Add
/// <summary>
/// Adds an object to the end of the MessageHeaderCollection
/// </summary>
/// <param name="MessageHeader">The Object to be added to the end of the MessageHeaderCollection.
/// The value can be a null reference (Nothing in Visual Basic). </param>
/// <returns>The MessageHeaderCollection index at which the value has been added.</returns>
public int Add( MessageHeader MessageHeader )
{
return( List.Add( MessageHeader ) );
}
#endregion
#region IndexOf
/// <summary>
/// Returns the zero-based index of the first occurrence of a
/// value in the MessageHeaderCollection or in a portion of it.
/// </summary>
/// <param name="value">The Object to locate in the MessageHeaderCollection. The value
/// can be a null reference (Nothing in Visual Basic). </param>
/// <returns></returns>
public int IndexOf( MessageHeader value )
{
return( List.IndexOf( value ) );
}
#endregion
#region Insert
/// <summary>
/// Inserts an element into the MessageHeaderCollection at
/// the specified index.
/// </summary>
/// <param name="index">The zero-based index at which value should be inserted</param>
/// <param name="MessageHeader">The MessageHeader to insert.
/// The value can be a null reference (Nothing in Visual Basic). </param>
public void Insert( int index, MessageHeader MessageHeader )
{
List.Insert( index, MessageHeader );
}
#endregion
#region Remove
/// <summary>
/// Removes the first occurrence of a
/// specific MessageHeader from the MessageHeaderCollection.
/// </summary>
/// <param name="MessageHeader">The object to remove from the MessageHeaderCollection</param>
public void Remove( MessageHeader MessageHeader )
{
List.Remove( MessageHeader );
}
#endregion
#region ToDataString
/// <summary>
/// Write the MessageHeaderCollection to a string that can be
/// included in an email.
/// </summary>
/// <returns>The String as it will appear in the resulting email.</returns>
public String ToDataString()
{
StringBuilder sb=new StringBuilder("");
foreach (MessageHeader messageheader in List)
{
sb.Append(messageheader.ToDataString());
}
return sb.ToString();
}
#endregion
}
}
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
namespace DotNetOpenMail
{
/// <summary>
/// A boundary which delimits a MIME object.
/// </summary>
internal class MimeBoundary
{
protected static readonly String MimeChars="abcdefghijklmnopqrstuvwxyz0123456789";
private String _theboundary=null;
private static Random random=new Random();
public MimeBoundary()
{
_theboundary=MakeMimeBoundary();
}
public String BoundaryString
{
get
{
return _theboundary;
}
}
public String BoundaryStringStart
{
get
{
return "--"+_theboundary;
}
}
public String BoundaryStringEnd
{
get
{
return "--"+_theboundary+"--";
}
}
private String MakeMimeBoundary()
{
int mimelength=32;
StringBuilder sb=new StringBuilder();
for (int i=0; i<MimeBoundary.MimeChars.Length; i++)
{
sb.Append(MimeChars[random.Next(mimelength)]);
}
return "_=DotNetOpenMail=_"+sb.ToString();
}
}
}
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.Collections;
namespace DotNetOpenMail
{
/// <summary>
/// A MIME container for content or other mime containers.
/// </summary>
internal class MimeContainer : IEmailStringable
{
private MimeBoundary _mimeboundary=null;
private ArrayList _attachments=new ArrayList();
private ArrayList _mimecontainers=new ArrayList();
private String _contenttype=null;
private bool _istoplevel=true;
public MimeContainer(MimeBoundary mimeboundary, String contenttype, bool istoplevel)
{
this._mimeboundary=mimeboundary;
this._contenttype=contenttype;
this._istoplevel=istoplevel;
}
public void AddAttachment(AbstractEmailAttachment attachment)
{
_attachments.Add(attachment);
}
public void AddMimeContainer(MimeContainer mimecontainer)
{
_mimecontainers.Add(mimecontainer);
}
private void WriteHeader(StringBuilder sb)
{
sb.Append("Content-Type: "+_contenttype+";"+SmtpProxy.ENDOFLINE);
sb.Append(" boundary=\""+_mimeboundary.BoundaryString+"\""+SmtpProxy.ENDOFLINE+SmtpProxy.ENDOFLINE);
//sb.Append(_mimeboundary.BoundaryStringStart+SmtpProxy.ENDOFLINE);
}
public String ToDataString()
{
StringBuilder sb=new StringBuilder();
bool hasheader=false;
if (!_istoplevel)
{
WriteHeader(sb);
}
foreach (MimeContainer mimecontainer in _mimecontainers)
{
hasheader=true;
sb.Append(_mimeboundary.BoundaryStringStart+SmtpProxy.ENDOFLINE);
sb.Append(mimecontainer.ToDataString());
//sb.Append(_mimeboundary.BoundaryStringEnd);
}
foreach (AbstractEmailAttachment attachment in _attachments)
{
hasheader=true;
sb.Append(_mimeboundary.BoundaryStringStart+SmtpProxy.ENDOFLINE);
sb.Append(attachment.ToDataString());
//sb.Append(_mimeboundary.BoundaryStringEnd);
}
if (hasheader)
{
sb.Append(_mimeboundary.BoundaryStringEnd+SmtpProxy.ENDOFLINE+SmtpProxy.ENDOFLINE);
}
return sb.ToString();
}
}
}
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail
{
/// <summary>
/// Create a RFC 2822-compliant date.
///
/// See section 3.3 in
/// http://ftp.rfc-editor.org/in-notes/rfc2822.txt
/// </summary>
public class RFC2822Date
{
private DateTime _datetime;
private TimeZone _timezone;
/// <summary>
/// Create an instance of the RFC 2822 date object.
/// </summary>
/// <param name="datetime">The date to convert</param>
/// <param name="timezone">The timezone to use in the conversion</param>
public RFC2822Date(DateTime datetime, TimeZone timezone)
{
this._datetime=datetime;
this._timezone=timezone;
}
/// <summary>
/// Generate the date string
/// </summary>
/// <returns>A RFC-2822 error code</returns>
public override String ToString()
{
TimeZone current=TimeZone.CurrentTimeZone;
TimeSpan timespan=current.GetUtcOffset(_datetime);
String tz=String.Format("{0:00}{1:00}", timespan.Hours, Math.Abs(timespan.Minutes %60));
if (timespan.TotalHours >= 0)
{
tz="+"+tz;
}
// Note: fixed for non-English default cultures; thanks, Angel Marin
return _datetime.ToString("ddd, d MMM yyyy HH:mm:ss "+tz, System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat);
}
}
}
@@ -0,0 +1,128 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail
{
/// <summary>
/// A full, preformatted email message, including headers
/// </summary>
public class RawEmailMessage : ISendableMessage
{
private String _content=null;
private EmailAddressCollection _rcpttoaddresses=new EmailAddressCollection();
private EmailAddress _mailfrom=null;
/// <summary>
/// Create an instance of the RawEmailMessage
/// </summary>
public RawEmailMessage()
{
}
#region Content
/// <summary>
/// The raw content of the email
/// </summary>
public String Content
{
get { return _content; }
set { _content = value; }
}
#endregion
#region MailFrom
/// <summary>
/// The address to use in the envelope-from
/// SMTP negotiation
/// </summary>
public EmailAddress MailFrom
{
get { return _mailfrom; }
set { _mailfrom = value; }
}
#endregion
#region RcptToAddresses
/// <summary>
/// The recipient addresses
/// </summary>
public EmailAddressCollection RcptToAddresses
{
get { return _rcpttoaddresses; }
}
#endregion
#region AddRcptToAddress
/// <summary>
/// Add a recipient to the EmailAddressCollection
/// of recipients
/// </summary>
/// <param name="emailaddress"></param>
public void AddRcptToAddress(EmailAddress emailaddress)
{
_rcpttoaddresses.Add(emailaddress);
}
#endregion
#region Send
/// <summary>
/// Send the email via the specified SMTP server
/// </summary>
/// <param name="smtpserver">The SMTP server to use</param>
/// <returns>true if the email was sent</returns>
public bool Send(SmtpServer smtpserver)
{
// smtpproxy=SmtpProxy.GetInstance(smtpserver);
if (_rcpttoaddresses.Count==0)
{
throw new MailException("Please include a RCPT TO address");
}
if (_mailfrom==null)
{
throw new MailException("Please include a MAIL FROM address");
}
return smtpserver.Send(this, _rcpttoaddresses, _mailfrom);
}
#endregion
#region ToDataString
/// <summary>
/// Render the message for smtp "DATA" transmission.
/// </summary>
/// <returns>The rendered String, which in this
/// case is the content itself, untouched.</returns>
public String ToDataString()
{
return _content;
}
#endregion
}
}
@@ -0,0 +1,170 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Resources;
namespace DotNetOpenMail.Resources
{
/// <summary>
/// ARM= Assembly Resource Manager. Manage the strings for the
/// various CultureInfo types.
/// </summary>
public sealed class ARM
{
/// <summary>
/// The singleton object
/// </summary>
private static ARM _theinstance=new ARM();
/// <summary>
/// The namespace of the resource files
/// </summary>
private string _pathname="DotNetOpenMail.Resources.DotNetOpenMail";
/// <summary>
/// The singleton System.Resources.ResourceManager.
/// </summary>
private ResourceManager _resources=null;
/// <summary>
/// Create the singleton
/// </summary>
private ARM()
{
_resources=new ResourceManager(_pathname, typeof(ARM).Assembly);
}
/// <summary>
/// Get the instance of the class
/// </summary>
/// <returns>the ARM instance</returns>
public static ARM GetInstance()
{
return _theinstance;
}
/// <summary>
/// Get an object from the file
/// </summary>
/// <param name="name">The key</param>
/// <returns>The key lookup for the default culture</returns>
public object GetObject(string name)
{
return GetObject(null, name);
}
/// <summary>
/// Get an object for the specified CultureInfo
/// </summary>
/// <param name="culture">The specified culture for the resource</param>
/// <param name="name">The key for the resource</param>
/// <returns>returns an object, if one is found, else null</returns>
public object GetObject(CultureInfo culture, string name)
{
if (_resources != null)
{
return _resources.GetObject(name, culture);
}
return null;
}
/// <summary>
/// Get a string for the specified CultureInfo for the
/// default culture
/// </summary>
/// <param name="name">The key for the resource</param>
/// <returns>returns a string, if one is found, else null</returns>
public string GetString(string name)
{
return GetString(null, name, null);
}
/// <summary>
/// Get a string for the specified CultureInfo for the
/// default culture. If not found, return defaultvalue
/// </summary>
/// <param name="name">The key for the resource</param>
/// <param name="defaultvalue">The value to return if there
/// is no value found.</param>
/// <returns>returns a string, if one is found, else defaultvalue</returns>
public string GetString(string name, string defaultvalue)
{
return GetString(null, name, defaultvalue);
}
/// <summary>
/// Get a string for the specified CultureInfo for the
/// current culture. If not found, return null
/// </summary>
/// <param name="culture">The culture of the resulting string</param>
/// <param name="name">The key for the resource</param>
/// <returns>returns a string, if one is found, else
/// null</returns>
public string GetString(CultureInfo culture, string name)
{
return GetString(culture, name, null);
}
/// <summary>
/// Get a string for the specified CultureInfo for the
/// default culture. If not found, return defaultvalue
/// </summary>
/// <param name="culture">The culture of the resulting string</param>
/// <param name="name">The key for the resource</param>
/// <param name="defaultvalue">The value to return if there
/// is no value found.</param>
/// <returns>returns a string, if one is found, else defaultvalue</returns>
public string GetString(CultureInfo culture, string name, string defaultvalue)
{
if (_resources != null)
{
String result=_resources.GetString(name, culture);
if (result==null)
{
return defaultvalue;
}
return result;
}
throw new ApplicationException("The Resources are uninitialized");
}
/// <summary>
/// Retrieve the entire resource set for this culture.
/// </summary>
/// <param name="culture">The culture to examine</param>
/// <returns>The resource set, if any.</returns>
public ResourceSet GetResourceSet(CultureInfo culture)
{
return _resources.GetResourceSet(culture, false, false);
}
}
}
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8" ?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="ResMimeType">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="Version">
<value>1.0.0.0</value>
</resheader>
<resheader name="Reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="Writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="no_subject">
<value>(no subject)</value>
</data>
<data name="this_is_mime">
<value>This is a multi-part message in MIME format</value>
</data>
<data name="unrecognized_auth_type">
<value>Unrecognized authentication type</value>
</data>
<data name="error_no_from">
<value>Please include a MAIL FROM address.</value>
</data>
</root>
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail.SmtpAuth
{
/// <summary>
/// Summary description for ISmtpAuthenticationToken.
/// </summary>
public interface ISmtpAuthToken
{
/// <summary>
/// The user's login
/// </summary>
String UserName
{
get; set;
}
/// <summary>
/// The user's password
/// </summary>
String Password
{
get; set;
}
/// <summary>
/// Negotiate AUTH with the SmtpProxy.
/// </summary>
/// <returns></returns>
SmtpResponse Negotiate(ISmtpProxy smtpProxy, String[] supportedAuthTypes);
}
}
@@ -0,0 +1,135 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
//using log4net;
using DotNetOpenMail.Encoding;
namespace DotNetOpenMail.SmtpAuth
{
/// <summary>
/// A LOCAL SMTP AUTH token
/// </summary>
public class LoginAuthToken : ISmtpAuthToken
{
//private static readonly ILog log = LogManager.GetLogger(typeof(LoginAuthToken));
private String _userName;
private String _password;
private System.Text.Encoding _charEncoding=System.Text.Encoding.GetEncoding("iso-8859-1");
/// <summary>
/// Create a new instance of the LOCAL SMTP
/// AUTH token
/// </summary>
public LoginAuthToken(String userName, String password)
{
this._userName=userName;
this._password=password;
}
/// <summary>
/// The User's password
/// </summary>
public String Password
{
get {return _password;}
set {_password=value;}
}
/// <summary>
/// The User's login
/// </summary>
public String UserName
{
get {return _userName;}
set {_userName=value;}
}
/*
/// <summary>
/// Return true if this is among the supported AUTH
/// types.
/// </summary>
/// <param name="authtypes"></param>
/// <returns></returns>
public bool IsSupported(SmtpAuthType[] authtypes)
{
log.Debug("CHECKING SUPPORTED TYPES");
for (int i=0; i<authtypes.Length; i++)
{
log.Debug("CHECKING IF "+authtypes[i]+"="+SmtpAuthType.Login);
if (authtypes[i]==SmtpAuthType.Login)
{
return true;
}
}
return false;
}
*/
/// <summary>
/// Return the 235 response code if valid, otherwise
/// return the error.
/// </summary>
/// <param name="smtpProxy"></param>
/// <param name="supportedAuthTypes">the supported auth types</param>
/// <returns></returns>
public SmtpResponse Negotiate(ISmtpProxy smtpProxy, String[] supportedAuthTypes)
{
SmtpResponse response=smtpProxy.Auth("login");
//log.Debug("RESPONSE WAS "+response.ResponseCode+" "+response.Message);
if (response.ResponseCode!=334)
{
return response;
}
Base64Encoder encoder=Base64Encoder.GetInstance();
response=smtpProxy.SendString(encoder.EncodeString(this.UserName, this._charEncoding ));
if (response.ResponseCode!=334)
{
return response;
}
response=smtpProxy.SendString(encoder.EncodeString(this.Password, this._charEncoding ));
if (response.ResponseCode!=334)
{
// here it's an error
return response;
}
else
{
// here it's ok.
return response;
}
}
}
}
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
//using log4net;
namespace DotNetOpenMail.SmtpAuth
{
/// <summary>
/// Summary description for SmtpAuthHelper.
/// </summary>
internal class SmtpAuthFactory
{
//private static readonly ILog log = LogManager.GetLogger(typeof(SmtpAuthFactory));
internal SmtpAuthFactory()
{
}
/// <summary>
/// Get the Auth type from the SMTP EHLO response.
/// If it is unrecognized or unimplemented,
/// return null. Case doesn't matter.
/// </summary>
/// <param name="authType">The string as returned in EHLO negotiation.</param>
/// <param name="username">The user's login</param>
/// <param name="password">The User's password</param>
internal static ISmtpAuthToken GetAuthTokenFromString(String authType, String username, String password)
{
authType=authType.ToLower().Trim();
if (authType.Equals("login"))
{
return new LoginAuthToken(username, password);
}
else
{
return null;
}
}
}
}
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
//using log4net;
namespace DotNetOpenMail.SmtpAuth
{
/// <summary>
/// Token which will negotiate an authentication type
/// with the server.
/// </summary>
public class SmtpAuthToken : ISmtpAuthToken
{
//private static readonly ILog log = LogManager.GetLogger(typeof(SmtpAuthToken));
private String _userName;
private String _password;
private System.Text.Encoding _charEncoding=System.Text.Encoding.GetEncoding("iso-8859-1");
/// <summary>
/// Create a new instance of the LOCAL SMTP
/// AUTH token
/// </summary>
public SmtpAuthToken(String userName, String password)
{
this._userName=userName;
this._password=password;
}
/// <summary>
/// The User's password
/// </summary>
public String Password
{
get {return _password;}
set {_password=value;}
}
/// <summary>
/// The User's login
/// </summary>
public String UserName
{
get {return _userName;}
set {_userName=value;}
}
/// <summary>
/// Return the 235 response code if valid, otherwise
/// return the error.
/// </summary>
/// <param name="smtpProxy">The SmtpProxy being used</param>
/// <param name="supportedAuthTypes">String array of EHLO-specified auth types</param>
/// <returns></returns>
public SmtpResponse Negotiate(ISmtpProxy smtpProxy, String[] supportedAuthTypes)
{
ISmtpAuthToken token=null;
foreach (String authType in supportedAuthTypes)
{
if (authType.Equals("login"))
{
token=new LoginAuthToken(_userName, _password);
break;
}
}
if (token==null)
{
return new SmtpResponse(504, DotNetOpenMail.Resources.ARM.GetInstance().GetString("unrecognized_auth_type"));
}
return token.Negotiate(smtpProxy, supportedAuthTypes);
}
}
}
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail
{
/// <summary>
/// An SmtpException represents an SMTP response
/// code and an error message. Network and connection
/// errors are represented by a MailException instead.
/// </summary>
public class SmtpException : Exception
{
private int _errorcode;
/// <summary>
/// Create a new instance of the SmtpException
/// </summary>
/// <param name="errorcode">The SMTP error code</param>
public SmtpException(int errorcode)
{
this._errorcode=errorcode;
}
/// <summary>
/// Create a new instance of the SmtpException
/// </summary>
/// <param name="errorcode">The SMTP error code</param>
/// <param name="message">The SMTP error message</param>
public SmtpException(int errorcode, string message) : base(message)
{
this._errorcode=errorcode;
}
/// <summary>
/// Create a new instance of the SmtpException
/// </summary>
/// <param name="errorcode">The SMTP error code</param>
/// <param name="message">The SMTP error message</param>
/// <param name="inner">The inner exception</param>
public SmtpException(int errorcode, string message, Exception inner) : base(message, inner)
{
this._errorcode=errorcode;
}
/// <summary>
/// The SMTP error code.
/// </summary>
public int ErrorCode
{
get {return _errorcode;}
set {_errorcode=value;}
}
/// <summary>
/// Convert to a string
/// </summary>
/// <returns></returns>
public override string ToString()
{
return _errorcode+" "+this.Message;
}
}
}
@@ -0,0 +1,516 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using DotNetOpenMail.SmtpAuth;
//using log4net;
namespace DotNetOpenMail
{
/// <summary>
/// A proxy to access an SMTP server. This drives
/// the protocol interaction.
/// </summary>
public class SmtpProxy : TcpClient, ISmtpProxy
{
//private static readonly ILog log = LogManager.GetLogger(typeof(SmtpProxy));
private SmtpServer _smtpserver=null;
internal static readonly String ENDOFLINE="\r\n";
private bool _isConnected=false;
private bool _captureConversation=false;
private static readonly String SERVER_LOG_PROMPT="READ> ";
private static readonly String CLIENT_LOG_PROMPT="SENT> ";
//private StringBuilder _conversation=new StringBuilder();
//private IPEndPoint _iEndPoint=null;
/*
#region SmtpProxy
private SmtpProxy(System.Net.IPAddress ipaddress, int portno)
{
_iendpoint = new IPEndPoint (ipaddress, portno);
}
#endregion
*/
#region SmtpProxy
private SmtpProxy(SmtpServer smtpserver)
{
_smtpserver=smtpserver;
}
#endregion
#region GetInstance
/// <summary>
/// Get an instance of the SMTP Proxy
/// </summary>
/// <param name="smtpserver"></param>
/// <returns></returns>
public static SmtpProxy GetInstance(SmtpServer smtpserver)
{
return new SmtpProxy(smtpserver);
}
#endregion
#region Open
/// <summary>
/// Connect to the server and return the initial
/// welcome string. Throw a MailException if we
/// can't connect.
/// </summary>
/// <returns></returns>
public SmtpResponse Open()
{
this.ReceiveTimeout=_smtpserver.ServerTimeout;
IPEndPoint ipendpoint=_smtpserver.GetIPEndPoint();
try
{
Connect(ipendpoint);
}
catch (Exception ex)
{
//throw new MailException("Could not connect to "+ipendpoint+":"+ipendpoint.Port, ex);
throw new MailException("Could not connect to "+ipendpoint, ex);
}
_isConnected=true;
return ReadSmtpResponse();
}
#endregion
#region Helo
/// <summary>
/// Send the HELO string.
/// Throw a MailException if we can't connect.
/// </summary>
/// <returns>the SMTP response</returns>
public SmtpResponse Helo(String localHostName)
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
String message = "HELO "+localHostName+SmtpProxy.ENDOFLINE;
//LogDebug("SENDING: "+message);
Write(message);
return ReadSmtpResponse();
}
#endregion
#region Ehlo
/// <summary>
/// Send the EHLO string.
/// Throw a MailException if we can't connect.
/// </summary>
/// <returns>the SMTP response</returns>
public EhloSmtpResponse Ehlo(String localHostName)
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
String message = "EHLO "+localHostName+SmtpProxy.ENDOFLINE;
//LogDebug("SENDING: "+message);
Write(message);
return ReadEhloSmtpResponse();
}
#endregion
#region MailFrom
/// <summary>
/// Send the MAIL FROM command
/// Throw a MailException if we can't connect.
/// </summary>
/// <param name="mailfrom">The Envelope-From address</param>
/// <returns>the SMTP response</returns>
public SmtpResponse MailFrom(EmailAddress mailfrom)
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
String message = "MAIL FROM: <"+mailfrom.Email+">"+SmtpProxy.ENDOFLINE;
Write(message);
return ReadSmtpResponse();
}
#endregion
#region RcptTo
/// <summary>
/// Send the MAIL FROM command
/// Throw a MailException if we can't connect.
/// </summary>
/// <param name="rcpttoaddress">A recipient's address</param>
/// <returns>the SMTP response</returns>
public SmtpResponse RcptTo(EmailAddress rcpttoaddress)
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
String message= "RCPT TO: <"+rcpttoaddress.Email+">"+SmtpProxy.ENDOFLINE;
//LogDebug("SENDING: "+message);
//OnLogWriteSmtp
Write(message);
return ReadSmtpResponse();
}
#endregion
#region Data
/// <summary>
/// Send the DATA string (without the data)
/// Throw a MailException if we can't connect.
/// </summary>
/// <returns>the SMTP response</returns>
public SmtpResponse Data()
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
String message = "DATA"+SmtpProxy.ENDOFLINE;
//LogDebug("SENDING: "+message);
Write(message);
return ReadSmtpResponse();
}
#endregion
#region WriteData
/// <summary>
/// Send the message content string
/// Throw a MailException if we can't
/// connect.
/// </summary>
/// <returns>the SMTP response</returns>
public SmtpResponse WriteData(String message)
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
StringReader reader=new StringReader(message);
String line=null;
while ((line=reader.ReadLine())!=null)
{
// checking for dot at the beginning of the
// line (RFC821 sec. 4.5.2)
if (line.Length > 0 && line[0]=='.')
{
Write("."+line+SmtpProxy.ENDOFLINE);
}
else
{
Write(line+SmtpProxy.ENDOFLINE);
}
}
Write(SmtpProxy.ENDOFLINE+"."+SmtpProxy.ENDOFLINE);
return ReadSmtpResponse();
}
#endregion
#region ReadSmtpResponse
private SmtpResponse ReadSmtpResponse()
{
String response=ReadResponse();
if (response.Length < 3)
{
throw new MailException("Invalid response from server: \""+response+"\"");
}
String responseCodeStr=response.Substring(0, 3);
String responseMessage="";
if (response.Length > 4)
{
responseMessage=response.Substring(4);
}
try
{
int responseCode=Convert.ToInt32(responseCodeStr);
return new SmtpResponse(responseCode, responseMessage);
}
catch
{
throw new MailException("Could not understand response from server: "+response);
}
}
#endregion
#region ReadEhloSmtpResponse
/// <summary>
/// Parse the response from the EHLO into an
/// EhloSmtpResponse. Returns 250 "OK" if successful.
/// </summary>
/// <returns></returns>
private EhloSmtpResponse ReadEhloSmtpResponse()
{
//log.Debug("READ THE RESPONSE");
EhloSmtpResponse ehloResponse=new EhloSmtpResponse();
String multiLineResponse=ReadResponse();
StringReader sr=new StringReader(multiLineResponse);
String line=null;
//log.Debug("READING...");
while ((line=sr.ReadLine()) !=null)
{
try
{
String responseMessage=String.Empty;
if (line.Length > 4)
{
responseMessage=line.Substring(4).Trim();
}
//log.Debug("Reading "+line);
int responseCode=Convert.ToInt32(line.Substring(0, 3));
if (responseCode==250)
{
if (responseMessage.ToLower().IndexOf("auth")==0)
{
// parse the auth types from the response
if (responseMessage.Length > 4)
{
// RFC 2554 SMTP Authentication:
// (3) The AUTH EHLO keyword contains as a parameter a space separated
// list of the names of supported SASL mechanisms.
foreach (String authtype in responseMessage.Substring(5).Split(' '))
{
ehloResponse.AddAvailableAuthType(authtype.ToLower());
}
}
// return new SmtpResponse(responseCode, responseMessage);
}
}
else
{
ehloResponse.ResponseCode=responseCode;
ehloResponse.Message=responseMessage;
return ehloResponse;
}
}
catch
{
throw new MailException("Could not understand response from server: "+multiLineResponse);
}
}
ehloResponse.ResponseCode=250;
ehloResponse.Message="OK";
return ehloResponse;
}
#endregion
#region Auth
/// <summary>
/// Send the AUTH command
/// Throw a MailException if we can't connect.
/// </summary>
/// <returns>the SMTP response</returns>
public SmtpResponse Auth(String authtype)
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
Write("AUTH "+authtype+SmtpProxy.ENDOFLINE);
return ReadSmtpResponse();
}
#endregion
#region SendString
/// <summary>
/// Send any old string to the proxy
/// </summary>
/// <returns>the SMTP response</returns>
public SmtpResponse SendString(String str)
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
Write(str+SmtpProxy.ENDOFLINE);
return ReadSmtpResponse();
}
#endregion
#region Write
/// <summary>
/// Write a string to the current connection.
/// </summary>
/// <param name="message"></param>
private void Write(string message)
{
try
{
//log.Debug(message);
_smtpserver.OnLogWriteSmtp(this, message);
if (_captureConversation)
{
_smtpserver.AppendConversation(SmtpProxy.CLIENT_LOG_PROMPT+message);
}
System.Text.ASCIIEncoding en = new System.Text.ASCIIEncoding() ;
byte[] WriteBuffer = new byte[1024] ;
WriteBuffer = en.GetBytes(message) ;
NetworkStream stream = GetStream() ;
if (!stream.CanWrite)
{
throw new MailException("Stream could not be opened for writing.");
}
stream.Write(WriteBuffer,0,WriteBuffer.Length);
}
catch (Exception ex)
{
//LogError(ex.Message);
throw new MailException("Error while sending data to the server: "+ex.Message, ex);
}
}
#endregion
#region Quit
/// <summary>
/// Send the QUIT command
/// Throw a MailException if we can't connect.
/// </summary>
/// <returns>the SMTP response</returns>
public SmtpResponse Quit()
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
Write("QUIT"+SmtpProxy.ENDOFLINE);
return ReadSmtpResponse();
}
#endregion
#region ReadResponse
private string ReadResponse()
{
try
{
System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"\d{3}\s.+");
string response = String.Empty;
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
byte[] serverbuff = new Byte[1024];
NetworkStream stream = GetStream();
if (!stream.CanRead)
{
throw new MailException("Stream could not be read.");
}
int count = 0;
// read until last response has been received
// (indicated by whitespace after the numerical response code)
do
{
int LoopTimeout = 0;
if (stream.DataAvailable)
{
count = stream.Read(serverbuff, 0, serverbuff.Length);
response = String.Concat(response, enc.GetString(serverbuff, 0, count));
}
if ((LoopTimeout += 100) > this._smtpserver.ServerTimeout)
{
throw new MailException("Multiline server response timed out");
}
Thread.Sleep(100);
}
while(! regex.IsMatch(response));
_smtpserver.OnLogReceiveSmtp(this, response);
if (_captureConversation)
{
this._smtpserver.AppendConversation(SmtpProxy.SERVER_LOG_PROMPT+response);
}
return response;
}
catch (Exception ex)
{
//LogError(ex.Message);
throw new MailException("Error while receiving data from server: "+ex.Message, ex);
}
}
#endregion
#region CaptureSmtpConversation
/// <summary>
/// Set this to "true" if you want to capture the SMTP negotiation.
/// Once the conversation has finished, use "GetConversation" to
/// view it.
/// </summary>
public bool CaptureSmtpConversation
{
get {return this._captureConversation;}
set {this._captureConversation=value;}
}
#endregion
/*
#region LogError
private void LogError(String message)
{
//System.Console.Error.WriteLine(message);
//log.Error(message);
}
#endregion
#region LogDebug
private void LogDebug(String message)
{
//System.Console.Out.WriteLine(message);
//log.Debug(message);
}
#endregion
*/
}
}
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail
{
/// <summary>
/// The response from the SMTP server
/// </summary>
public class SmtpResponse
{
private int _responseCode;
private String _message;
/// <summary>
/// Create an instance of the SmtpResponse
/// </summary>
/// <param name="responseCode"></param>
/// <param name="message"></param>
public SmtpResponse(int responseCode, String message)
{
this._responseCode=responseCode;
this._message=message;
}
/// <summary>
/// The SMTP Reponse code
/// </summary>
public int ResponseCode
{
get { return _responseCode; }
}
/// <summary>
/// The SMTP Response String
/// </summary>
public String Message
{
get { return _message; }
}
/// <summary>
/// Was the response a fatal error?
/// </summary>
public bool IsFatalError
{
get {
return (this._responseCode>=500 && this._responseCode <= 599);
}
}
/// <summary>
/// Was the response an OK message?
/// </summary>
public bool IsOk
{
get
{
return (this._responseCode>=200 && this._responseCode <= 299);
}
}
/// <summary>
/// Convert this response to an exception
/// </summary>
/// <returns>The SmtpException corresponding to this response</returns>
public SmtpException GetException()
{
return new SmtpException(this._responseCode, this._message);
}
}
}
@@ -0,0 +1,179 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail
{
/// <summary>
/// SMTP server response codes and their meanings.
/// </summary>
public enum SmtpResponseCode: int
{
/// <remarks>
/// System status, or system help reply.
/// </remarks>
SystemStatus = 211,
/// <remarks>
/// Help message.
/// </remarks>
Help = 214,
/// <remarks>
/// Domain service ready. Ready to start TLS.
/// </remarks>
HeloReply = 220,
/// <remarks>
/// Domain service closing transmission channel.
/// </remarks>
Quit = 221,
/// <remarks>
/// Authentication successfully completed.
/// </remarks>
AuthSuccessful = 235,
/// <remarks>
/// OK, queuing for node node started. Requested mail action completed.
/// </remarks>
Ok = 250,
/// <remarks>
/// OK, no messages waiting for node node. User not local, will forward to forwardpath.
/// </remarks>
OkWillForward = 251,
/// <remarks>
/// OK, pending messages for node node started. Cannot VRFY user (e.g., info is not local), but will take message for this user and attempt delivery.
/// </remarks>
OkWithoutVerify = 252,
/// <remarks>
/// OK, messages pending messages for node node started.
/// </remarks>
OkMsgStarted = 253,
/// <remarks>
/// Start mail input, end with CRLF.CRLF
/// </remarks>
StartMailInput = 354,
/// <remarks>
/// Octet-offset is the transaction offset.
/// </remarks>
TransactionOffset = 355,
/// <remarks>
/// Domain service not available, closing transmission channel.
/// </remarks>
ServiceNotAvailable = 421,
/// <remarks>
/// A password transition is needed.
/// </remarks>
PasswordNeeded = 432,
/// <remarks>
/// Requested mail action not taken: mailbox unavailable.
/// </remarks>
MailboxBusy = 450,
/// <remarks>
/// Requested action aborted: local error in processing. Unable to process ATRN request now.
/// </remarks>
ErrorProcessing = 451,
/// <remarks>
/// Requested action not taken: insufficient system storage.
/// </remarks>
InsufficientStorage = 452,
/// <remarks>
/// You have no mail.
/// </remarks>
NoMail = 453,
/// <remarks>
/// TLS not available. Encryption required for requested authentication mechanism.
/// </remarks>
TlsNotAvailable = 454,
/// <remarks>
/// Unable to queue messages for node node.
/// </remarks>
NoMsgQueue = 458,
/// <remarks>
/// Node node not allowed: reason.
/// </remarks>
NodeNotAllowed = 459,
/// <remarks>
/// Command not recognized: command. Syntax error.
/// </remarks>
UnknownCmd = 500,
/// <remarks>
/// Syntax error, no parameters allowed.
/// </remarks>
SyntaxError = 501,
/// <remarks>
/// Command not implemented.
/// </remarks>
CmdNotImplemented = 502,
/// <remarks>
/// Bad sequence of commands.
/// </remarks>
BadSequence = 503,
/// <remarks>
/// Command parameter not implemented.
/// </remarks>
ParamNotImplemented = 504,
/// <remarks>
/// Security error.
/// </remarks>
SecurityError = 505,
/// <remarks>
/// Machine does not accept mail.
/// </remarks>
MailNotAccepted = 521,
/// <remarks>
/// Must issue a STARTTLS command first. Encryption required for requested authentication mechanism.
/// </remarks>
StartTLSneeded = 530,
/// <remarks>
/// Authentication mechanism is too weak.
/// </remarks>
AuthTooWeak = 534,
/// <remarks>
/// Encryption required for requested authentication mechanism.
/// </remarks>
EncryptionRequired = 538,
/// <remarks>
/// Requested action not taken: mailbox unavailable.
/// </remarks>
ActionNotTaken = 550,
/// <remarks>
/// User not local, please try forward path.
/// </remarks>
NotLocalPleaseForward = 551,
/// <remarks>
/// Requested mail action aborted: exceeded storage allocation.
/// </remarks>
ExceedStorageAllowance = 552,
/// <remarks>
/// Requested action not taken: mailbox name not allowed.
/// </remarks>
MailboxNameNotAllowed = 553,
/// <remarks>
/// Transaction failed.
/// </remarks>
TransactionFailed = 554
}
}
@@ -0,0 +1,532 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Net;
using System.Text;
using DotNetOpenMail.SmtpAuth;
using DotNetOpenMail.Logging;
//using DomainKeys;
namespace DotNetOpenMail
{
/// <summary>
/// A description of an SMTP server.
/// </summary>
public class SmtpServer
{
//public delegate void SmtpDataMessagePresendHandler(object sender, MyEventArgs e);
/// <summary>
/// Logging delegate
/// </summary>
public delegate void LogHandler(LogMessage logMessage);
/// <summary>
/// Handle a message about to be sent
/// </summary>
public event LogHandler LogSmtpWrite;
/// <summary>
/// Handle a message received
/// </summary>
public event LogHandler LogSmtpReceive;
/// <summary>
/// Log that the conversation has completed
/// </summary>
public event LogHandler LogSmtpCompleted;
//private static Logger _logger=new Logger();
#region Data Members
private IPEndPoint _ipendpoint;
private IPAddress _ipaddress;
private String _hostname;
private int _port=25;
private String _id; // some human readable name
private int _serverTimeout=30000; // the timeout in milliseconds
private String _helohost=null;
private ISmtpAuthToken _authToken=null;
private ISmtpProxy _smtpProxy=null;
private bool _captureSmtpConversation=false;
private StringBuilder _smtpConversation=new StringBuilder();
#endregion
#region SmtpServer
/// <summary>
/// Create a new SMTP server at this hostname and
/// port.
/// </summary>
/// <param name="hostname">The address or hostname of the smtp server</param>
/// <param name="port">The port of the smtp server.</param>
public SmtpServer(String hostname, int port)
{
_id=hostname+":"+port;
_hostname=hostname;
_port=port;
}
#endregion
#region SmtpServer
/// <summary>
/// Create a new SMTP server at this hostname and
/// port.
/// </summary>
/// <param name="hostname">The address or hostname of the smtp server</param>
public SmtpServer(String hostname)
{
_id=hostname+":"+_port;
_hostname=hostname;
}
#endregion
#region SmtpServer
/// <summary>
/// Create a new SMTP server at this hostname and
/// port.
/// </summary>
/// <param name="ipaddress">The ip address of the SMTP server</param>
/// <param name="port">The port number of SMTP server</param>
public SmtpServer(IPAddress ipaddress, int port)
{
_id=ipaddress.ToString()+":"+port;
_ipaddress=ipaddress;
_port=port;
}
#endregion
#region GetIPEndPoint
/// <summary>
/// Get the end point for the SMTP server. The IPEndpoint will
/// be saved for later to prevent multiple hostname lookups.
/// </summary>
/// <exception>SmtpException is thrown if the host doesn't resolve.</exception>
/// <returns>returns an IPEndPoint for the SMTPServer.</returns>
internal IPEndPoint GetIPEndPoint()
{
if (_ipendpoint!=null)
{
return _ipendpoint;
}
if (_hostname!=null)
{
IPHostEntry iphostentry=System.Net.Dns.Resolve(_hostname);
if (iphostentry.AddressList.Length==0)
{
throw new MailException("unable to resolve host: "+_hostname);
}
else
{
_ipendpoint=new IPEndPoint(iphostentry.AddressList[0], _port);
}
return this._ipendpoint;
}
else if (_ipaddress!=null)
{
_ipendpoint=new IPEndPoint(_ipaddress, _port);
return _ipendpoint;
}
else throw new MailException("Invalid IPEndPoint");
}
#endregion
#region ServerTimeout
/// <summary>
/// The timeout waiting for an SMTP command, in
/// milliseconds
/// </summary>
public int ServerTimeout
{
get {return _serverTimeout;}
set {_serverTimeout=value;}
}
#endregion
#region GetSmtpProxy
/// <summary>
/// Get an instance of an SmtpProxy
/// </summary>
/// <returns></returns>
internal ISmtpProxy GetSmtpProxy()
{
if (_smtpProxy!=null)
{
return _smtpProxy;
}
else
{
return SmtpProxy.GetInstance(this);
}
}
#endregion
#region GetHeloHost
private String GetHeloHost()
{
if (_helohost!=null)
{
return _helohost;
}
else
{
//String hostname=Environment.MachineName.ToLower();
String hostname=Dns.GetHostName();
if (hostname!=null)
{
return hostname;
}
else
{
return "localhost";
}
}
}
#endregion
#region UseEhlo
/// <summary>
/// Figure out whether we need EHLO or not.
/// Currently, this is only for SMTP AUTH
/// </summary>
/// <returns></returns>
private bool UseEhlo()
{
if (this._authToken!=null)
{
return true;
}
else
{
return false;
}
}
#endregion
#region Send
/// <summary>
/// Send the email.
/// </summary>
/// <param name="emailMessage">The completed message</param>
/// <param name="rcpttocollection">A list of email addresses which
/// are to be used in the RCPT TO SMTP communication</param>
/// <param name="mailfrom">An email address for the MAIL FROM
/// part of the SMTP protocol.</param>
/// <exception cref="SmtpException">throws an SmtpException if there
/// is an unexpected SMTP error number sent from the server.</exception>
/// <exception cref="MailException">throws a MailException if there
/// is a network problem, connection problem, or other issue.</exception>
/// <returns></returns>
internal bool Send(ISendableMessage emailMessage, EmailAddressCollection rcpttocollection, EmailAddress mailfrom)
{
//ISmtpNegotiator negotiator=_smtpserver.GetSmtpNegotiator();
ISmtpProxy smtpproxy=GetSmtpProxy();
//smtpproxy.CaptureSmtpConversation=CaptureSmtpConversation;
SmtpResponse smtpResponse=smtpproxy.Open();
try
{
#region Connect
if (smtpResponse.ResponseCode!=220)
{
throw smtpResponse.GetException();
}
#endregion
#region HELO / EHLO
if (UseEhlo())
{
EhloSmtpResponse esmtpResponse=smtpproxy.Ehlo(GetHeloHost());
if (esmtpResponse.ResponseCode!=250)
{
// TODO: FIX THIS
throw new SmtpException(esmtpResponse.ResponseCode, esmtpResponse.Message);
}
// do SMTP AUTH
if (this._authToken!=null)
{
smtpResponse=_authToken.Negotiate(smtpproxy, esmtpResponse.GetAvailableAuthTypes());
if (smtpResponse.ResponseCode!=235)
{
throw smtpResponse.GetException();
}
}
}
else
{
smtpResponse=smtpproxy.Helo(GetHeloHost());
if (smtpResponse.ResponseCode!=250)
{
throw smtpResponse.GetException();
}
}
#endregion
#region MAIL FROM
smtpResponse=smtpproxy.MailFrom(mailfrom);
if (smtpResponse.ResponseCode!=250)
{
throw smtpResponse.GetException();
}
#endregion
#region RCPT TO
foreach ( EmailAddress rcpttoaddress in rcpttocollection)
{
smtpResponse=smtpproxy.RcptTo(rcpttoaddress);
if (smtpResponse.ResponseCode!=250)
{
throw smtpResponse.GetException();
}
}
#endregion
#region DATA
smtpResponse=smtpproxy.Data();
if (smtpResponse.ResponseCode!=354)
{
throw smtpResponse.GetException();
}
//smtpResponse=negotiator.WriteData();
String message=emailMessage.ToDataString();
if (message==null)
{
throw new MailException("The message content is null");
}
/*
// START Test With Domain Keys
// (this would appear as an event callback if it works)
MailSigner mailsigner=new MailSigner();
bool signed = mailsigner.signMail(message);
if (!signed)
{
throw new MailException("Error creating DomainKeys signature.");
}
message=mailsigner.signedHeader + message;
// END Test With Domain Keys
*/
// Send the data
smtpResponse=smtpproxy.WriteData(message);
if (smtpResponse.ResponseCode!=250)
{
throw smtpResponse.GetException();
}
#endregion
#region QUIT
// QUIT
smtpResponse=smtpproxy.Quit();
if (smtpResponse.ResponseCode!=221)
{
throw smtpResponse.GetException();
}
#endregion
}
finally
{
smtpproxy.Close();
OnLogSmtpCompleted(this, "Connection Closed");
}
return true;
}
#endregion
#region OverrideSmtpProxy
/// <summary>
/// Override the SmtpProxy. This is only
/// for testing smtp negotiation without an
/// smtp server.
/// </summary>
/// <param name="smtpProxy"></param>
public void OverrideSmtpProxy(ISmtpProxy smtpProxy)
{
_smtpProxy=smtpProxy;
}
#endregion
#region SmtpAuthToken
/// <summary>
/// Get or set the SMTP AUTH token for the server.
/// </summary>
public ISmtpAuthToken SmtpAuthToken
{
get {return _authToken;}
set {_authToken = value;}
}
#endregion
#region CaptureSmtpConversation
/// <summary>
/// If true, the following call to "Send" will capture the
/// most recent SMTP conversation to the SmtpServer object.
/// This is intended for debugging only.
/// This is deprecated in favour of the log message events.
/// </summary>
[ObsoleteAttribute("This property is deprecated. You "+
"should use LogSmtpWrite and LogSmtpReceive instead. "+
"This will be removed in a future version.", false)]
public bool CaptureSmtpConversation
{
get
{
return _captureSmtpConversation;
}
set
{
_captureSmtpConversation=value;
if (!_captureSmtpConversation)
{
this._smtpConversation=new StringBuilder();
}
}
}
#endregion
#region AppendConversation
/// <summary>
/// Append this string to the conversation log.
/// </summary>
/// <param name="str">the string from the SMTP conversation</param>
internal void AppendConversation(String str)
{
this._smtpConversation.Append(str);
}
#endregion
#region GetSmtpConversation
/// <summary>
/// If CaptureSmtpConversation is true, a Send() will
/// be captured, and will be accessible here.
/// </summary>
/// <returns>The SMTP Conversation or null.</returns>
[ObsoleteAttribute("This method is deprecated. You "+
"should use LogSmtpWrite and LogSmtpReceive instead. "+
"This will be removed in a future version.", false)]
public String GetSmtpConversation()
{
if (_smtpConversation==null || _smtpConversation.Length==0)
{
return null;
}
else
{
return _smtpConversation.ToString();
}
}
#endregion
#region OnLogWriteSmtp
internal void OnLogWriteSmtp(Object sender, String message)
{
if (LogSmtpWrite!=null)
{
LogSmtpWrite(new LogMessage(sender, message));
}
}
#endregion
#region OnLogReceiveSmtp
internal void OnLogReceiveSmtp(Object sender, String message)
{
if (LogSmtpReceive!=null)
{
LogSmtpReceive(new LogMessage(sender, message));
}
}
#endregion
#region OnLogSmtpCompleted
internal void OnLogSmtpCompleted(Object sender, String message)
{
if (LogSmtpCompleted!=null)
{
LogSmtpCompleted(new LogMessage(sender, message));
}
}
#endregion
#region Hostname
/// <summary>
/// The server hostname
/// </summary>
public String Hostname
{
get {return _hostname;}
}
#endregion
#region Port
/// <summary>
/// The server port
/// </summary>
public int Port
{
get {return _port;}
}
#endregion
/// <summary>
/// Return the host name, a colon, and a port number.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return Hostname+":"+Port;
}
/// <summary>
/// Set the hostname used by the HELO
/// command.
/// </summary>
public String HeloHost
{
get
{
return _helohost;
}
set
{
_helohost=value;
}
}
}
}
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using DotNetOpenMail.Encoding;
using DotNetOpenMail.Utils;
namespace DotNetOpenMail
{
/// <summary>
/// A mime representation of plain-text content.
/// </summary>
public class TextAttachment : AbstractEmailAttachment
{
//private IEncoder _encoder=null;
//private String _mimetype="text/plain";
/// <summary>
/// Create a new plain-text Attachment. It flags the content/type
/// as "text/plain", uses Quoted Printable encoding by
/// default, and uses the default character set, which is
/// ISO-8859-1 unless otherwise specified in the .config file.
/// </summary>
/// <param name="contents"></param>
public TextAttachment(String contents)
{
this.ContentType="text/plain";
this.Contents=contents;
this.CharSet=System.Text.Encoding.GetEncoding(Configuration.GetInstance().GetDefaultEncoding("iso-8859-1"));
//this.Encoder=EncoderFactory.GetEncoder(EncodingType.QuotedPrintable);
this.Encoding=EncodingType.QuotedPrintable;
}
}
}
@@ -0,0 +1,58 @@
using System;
using System.IO;
namespace DotNetOpenMail.Utils
{
/// <summary>
/// Something take a binary reader's data into a byte array.
/// </summary>
public class BinaryReaderUtil
{
/// <summary>
/// Constructor for BinaryReaderUtil
/// </summary>
public BinaryReaderUtil()
{
}
/// <summary>
/// Read a binary stream into a byte array
/// (Cribbed from posting by Jon Skeet:
/// http://www.developerfusion.co.uk/show/4696/)
/// </summary>
/// <param name="binaryreader">An open Binary Reader</param>
/// <returns>A byte array with the bytes from the disk</returns>
public static byte[] ReadIntoByteArray (BinaryReader binaryreader)
{
int initialLength = 32768;
byte[] buffer = new byte[initialLength];
int read=0;
int chunk;
while ( (chunk = binaryreader.Read(buffer, read, buffer.Length-read)) > 0)
{
read += chunk;
if (read == buffer.Length)
{
int nextByte = binaryreader.ReadByte();
if (nextByte==-1)
{
return buffer;
}
byte[] newBuffer = new byte[buffer.Length*2];
Array.Copy(buffer, newBuffer, buffer.Length);
newBuffer[read]=(byte)nextByte;
buffer = newBuffer;
read++;
}
}
byte[] ret = new byte[read];
Array.Copy(buffer, ret, read);
return ret;
}
}
}
@@ -0,0 +1,112 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail.Utils
{
/// <summary>
/// An interface to the configuration settings for the library.
/// This includes an interface to the .config file.
/// This is a singleton.
/// </summary>
public class Configuration
{
/// <summary>
/// The singleton
/// </summary>
private static Configuration _theinstance=new Configuration();
/// <summary>
/// Empty constructor
/// </summary>
private Configuration()
{
}
/// <summary>
/// Instantiate the instance of the object (if not created)
/// and return it.
/// </summary>
/// <returns>the Configuration singleton object</returns>
public static Configuration GetInstance()
{
return _theinstance;
}
/// <summary>
/// Get the X-Sender header, if any is specified in the .config
/// file with the key dnom.headers.xsender.
/// </summary>
/// <returns></returns>
public String GetXSender()
{
return System.Configuration.ConfigurationSettings.AppSettings["dnom.headers.xsender"];
}
/// <summary>
/// Get the default encoding, if any is specified in the .config
/// file with the key dnom.encoding.
/// </summary>
public String GetDefaultEncoding(String def)
{
return GetAppSetting("dnom.encoding", def);
}
/// <summary>
/// Get the default charset, if any is specified in the .config
/// file with the key dnom.charset.
/// </summary>
public System.Text.Encoding GetDefaultCharset()
{
String encodingstr=GetAppSetting("dnom.encoding", "iso-8859-1");
return System.Text.Encoding.GetEncoding(encodingstr);
}
/// <summary>
/// Get an app setting from the .config file. If none is found
/// or it is empty or only whitespace, use the defaultvalue.
/// </summary>
/// <param name="key">The key to search for in the .config file</param>
/// <param name="defaultvalue">The default value if the value
/// is null or only whitespace.</param>
private String GetAppSetting(String key, String defaultvalue)
{
String tmp=System.Configuration.ConfigurationSettings.AppSettings[key];
if (tmp==null || tmp.Trim()=="")
{
return defaultvalue;
}
else
{
return tmp;
}
}
}
}
@@ -0,0 +1,114 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.Text.RegularExpressions;
namespace DotNetOpenMail.Utils
{
/// <summary>
/// Parse a email address string into an EmailAddress.
/// * This isn't very mature yet! *
/// </summary>
public class EmailAddressParser
{
private String _lastError=null;
/// <summary>
/// Constructor
/// </summary>
public EmailAddressParser()
{
}
/// <summary>
/// If the last conversion was unsuccessful, this
/// contains the error message. If it was successful,
/// it will be null.
/// </summary>
public String LastError
{
get {return _lastError;}
}
/// <summary>
/// Parse a raw email address into an EmailAddress object.
/// If it can't be parsed, return null and set LastError
/// to the error message.
/// </summary>
/// <param name="rawemailaddress"></param>
/// <returns></returns>
public EmailAddress ParseRawEmailAddress(String rawemailaddress)
{
// see: http://www.twilightsoul.com/Default.aspx?PageContentID=10&tabid=134
String regex=@"^((?<DisplayName>([\t\x20]*[!#-'\*\+\-/-9=\?A-Z\^-~]+[\t\x20]*|"""+
@"[\x01-\x09\x0B\x0C\x0E-\x21\x23-\x5B\x5D-\x7F]*"")+)?[\t\x20]*"+
@"<(?<LocalPart>([\t\x20]*[!#-'\*\+\-/-9=\?A-Z\^-~]+"+
@"(\.[!#-'\*\+\-/-9=\?A-Z\^-~]+)*|""[\x01-\x09\x0B\x0C\x0E-\x21\x23-\x5B\x5D-\x7F]*""))"+
@"@(?<Domain>(([a-zA-Z0-9][-a-zA-Z0-9]*[a-zA-Z0-9]\.)+[a-zA-Z]{2,}|"+
@"\[(([0-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}"+
@"([0-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\]"+
@"|[a-zA-Z0-9_-]+"+ // added to allow domains w/o dot, e.g. "localhost"
@"))>[\t\x20]*|"+
@"(?<LocalPart>([\t\x20]*[!#-'\*\+\-/-9=\?A-Z\^-~]+(\.[!#-'\*\+\"+
@"-/-9=\?A-Z\^-~]+)*|"+
@"""[\x01-\x09\x0B\x0C\x0E-\x21\x23-\x5B\x5D-\x7F]*""))"+
@"@(?<Domain>(([a-zA-Z0-9][-a-zA-Z0-9]*[a-zA-Z0-9]\.)+[a-zA-Z]{2,}|"+
@"\[(([0-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}"+ // IP line 1
@"([0-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\]"+ // IP line 2
@")))$";
Regex re = new Regex(regex, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
Match m = re.Match(rawemailaddress);
String email="";
String name="";
if (!m.Success)
{
_lastError="Could not parse the email address: "+rawemailaddress;
return null;
}
else
{
_lastError=null;
name=m.Groups["DisplayName"].Value.Trim();
email=m.Groups["LocalPart"].Value;
String domain=m.Groups["Domain"].Value;
if (!domain.Equals(""))
{
email+="@"+domain;
}
}
return new EmailAddress(email, name);
}
}
}
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail.Utils
{
/// <summary>
/// The DotNetOpenMail Version.
/// </summary>
public class VersionInfo
{
private static VersionInfo _theobject=new VersionInfo();
private int majorid=0;
private int minorid=5;
private int incidentalid=8;
private String status="b"; // "a" is for alpha, "b" for beta, "rcX" for release candidate,
//"" for release
/// <summary>
/// Empty Constructor
/// </summary>
private VersionInfo()
{
}
/// <summary>
/// Get the singleton of this class
/// </summary>
/// <returns></returns>
public static VersionInfo GetInstance()
{
return new VersionInfo();
}
/// <summary>
/// Get the current version info as a printable string.
/// This will be of the form A.B.CD, where A is the
/// majorid, B is the minor id, C is the incidental revision,
/// and D is either "a", "b", "rcX" for "alpha", "beta" and
/// "release candidate X", respectively. If it is the
/// release version, D is blank.
/// </summary>
/// <returns></returns>
public override String ToString()
{
return String.Format("{0}.{1}.{2}{3}", majorid, minorid, incidentalid, status);
}
}
}
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System.Reflection;
using System.Runtime.CompilerServices;
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly: AssemblyTitle("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: log4net.Config.DOMConfigurator(ConfigFileExtension="log4net", Watch=true)]
[assembly: log4net.Config.Domain()]
//
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
//
// In order to sign your assembly you must specify a key to use. Refer to the
// Microsoft .NET Framework documentation for more information on assembly signing.
//
// Use the attributes below to control which key is used for signing.
//
// Notes:
// (*) If no key is specified, the assembly is not signed.
// (*) KeyName refers to a key that has been installed in the Crypto Service
// Provider (CSP) on your machine. KeyFile refers to a file which contains
// a key.
// (*) If the KeyFile and the KeyName values are both specified, the
// following processing occurs:
// (1) If the KeyName can be found in the CSP, that key is used.
// (2) If the KeyName does not exist and the KeyFile does exist, the key
// in the KeyFile is installed into the CSP and used.
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
// When specifying the KeyFile, the location of the KeyFile should be
// relative to the project output directory which is
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
// located in the project directory, you would specify the AssemblyKeyFile
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
// documentation for more information on this.
//
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]
@@ -0,0 +1,251 @@
<VisualStudioProject>
<CSHARP
ProjectType = "Local"
ProductVersion = "7.10.3077"
SchemaVersion = "2.0"
ProjectGuid = "{74F3DCD7-1325-4968-B466-38618A380CE9}"
>
<Build>
<Settings
ApplicationIcon = ""
AssemblyKeyContainerName = ""
AssemblyName = "DotNetOpenMailTests"
AssemblyOriginatorKeyFile = ""
DefaultClientScript = "JScript"
DefaultHTMLPageLayout = "Grid"
DefaultTargetSchema = "IE50"
DelaySign = "false"
OutputType = "Library"
PreBuildEvent = ""
PostBuildEvent = 'copy "$(SolutionDir)DotNetOpenMailTests.dll.*" "$(ProjectDir)$(OutDir)"'
RootNamespace = "DotNetOpenMailTests"
RunPostBuildEvent = "OnBuildSuccess"
StartupObject = ""
>
<Config
Name = "Debug"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "DEBUG;TRACE"
DocumentationFile = ""
DebugSymbols = "true"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "false"
OutputPath = "bin\Debug\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
<Config
Name = "Release"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "TRACE"
DocumentationFile = ""
DebugSymbols = "false"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "true"
OutputPath = "bin\Release\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
</Settings>
<References>
<Reference
Name = "System"
AssemblyName = "System"
HintPath = "..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.dll"
/>
<Reference
Name = "System.Data"
AssemblyName = "System.Data"
HintPath = "..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Data.dll"
/>
<Reference
Name = "System.XML"
AssemblyName = "System.Xml"
HintPath = "..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.XML.dll"
/>
<Reference
Name = "log4net"
AssemblyName = "log4net"
HintPath = "..\lib\log4net.dll"
/>
<Reference
Name = "nunit.framework"
AssemblyName = "nunit.framework"
HintPath = "..\lib\nunit.framework.dll"
/>
<Reference
Name = "DotNetOpenMail"
Project = "{6FBB299F-81A1-49EA-B00A-E916F8F797B3}"
Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
/>
<Reference
Name = "System.Web"
AssemblyName = "System.Web"
HintPath = "..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Web.dll"
/>
<Reference
Name = "nmock"
AssemblyName = "nmock"
HintPath = "..\lib\nmock.dll"
/>
</References>
</Build>
<Files>
<Include>
<File
RelPath = "AssemblyInfo.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "EmailAddressTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "EmailMessageInAlternateEncodings.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "EmailMessageTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ExampleTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "FileAttachmentTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "FileAttachmentTests2.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Log4netLogger.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "QuickTest.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "RawEmailMessageTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "RFC2822DateTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "RussianTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SmtpProxyTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "TestAddressHelper.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Encoding\Base64EncoderTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Encoding\EightBitEncoderTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Encoding\QPEncoderTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Encoding\SevenBitEncoderTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Resources\ARMTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SmtpAuth\LocalAuthTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SmtpAuth\MockedSlowProxy.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SmtpAuth\MockedSmtpProxy.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "SmtpServerTests\SmtpServerTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "TestFiles\grover.jpg"
BuildAction = "Content"
/>
<File
RelPath = "TestFiles\grover.tif"
BuildAction = "Content"
/>
<File
RelPath = "TestFiles\groverUpsideDown.jpg"
BuildAction = "Content"
/>
<File
RelPath = "TestFiles\ImportedEmail.txt"
BuildAction = "Content"
/>
<File
RelPath = "Utils\EmailAddressParserTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
</Include>
</Files>
</CSHARP>
</VisualStudioProject>
@@ -0,0 +1,48 @@
<VisualStudioProject>
<CSHARP LastOpenVersion = "7.10.3077" >
<Build>
<Settings ReferencePath = "C:\Visual Studio Projects\DotNetOpenMail\lib\" >
<Config
Name = "Debug"
EnableASPDebugging = "false"
EnableASPXDebugging = "false"
EnableUnmanagedDebugging = "false"
EnableSQLServerDebugging = "false"
RemoteDebugEnabled = "false"
RemoteDebugMachine = ""
StartAction = "Project"
StartArguments = ""
StartPage = ""
StartProgram = ""
StartURL = ""
StartWorkingDirectory = ""
StartWithIE = "false"
/>
<Config
Name = "Release"
EnableASPDebugging = "false"
EnableASPXDebugging = "false"
EnableUnmanagedDebugging = "false"
EnableSQLServerDebugging = "false"
RemoteDebugEnabled = "false"
RemoteDebugMachine = ""
StartAction = "Project"
StartArguments = ""
StartPage = ""
StartProgram = ""
StartURL = ""
StartWorkingDirectory = ""
StartWithIE = "true"
/>
</Settings>
</Build>
<OtherProjectSettings
CopyProjectDestinationFolder = ""
CopyProjectUncPath = ""
CopyProjectOption = "0"
ProjectView = "ShowAllFiles"
ProjectTrust = "0"
/>
</CSHARP>
</VisualStudioProject>
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using DotNetOpenMail;
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests {
[TestFixture]
public class EmailAddressTests {
private static readonly ILog log = LogManager.GetLogger(typeof(EmailAddressTests));
public EmailAddressTests() {
}
[SetUp]
public void SetUp() {}
[TearDown]
public void TearDown() {}
[Test]
public void TestSerialization()
{
EmailAddress emailaddress=new EmailAddress("test@test.com", "My Name");
Assert.AreEqual("My Name <test@test.com>",emailaddress.ToString());
emailaddress=new EmailAddress("test@test.com", "Last, First");
Assert.AreEqual("\"Last, First\" <test@test.com>",emailaddress.ToString());
emailaddress=new EmailAddress("test@test.com", "<First Last>");
Assert.AreEqual("\"<First Last>\" <test@test.com>",emailaddress.ToString());
emailaddress=new EmailAddress("test@test.com", "[First Last]");
Assert.AreEqual("\"[First Last]\" <test@test.com>",emailaddress.ToString());
emailaddress=new EmailAddress("test@test.com", "(First Last)");
Assert.AreEqual("\"(First Last)\" <test@test.com>",emailaddress.ToString());
emailaddress=new EmailAddress("test@test.com", "First \"NickName\" Last");
Assert.AreEqual("\"First \\\"NickName\\\" Last\" <test@test.com>",emailaddress.ToString());
}
}
}
@@ -0,0 +1,307 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.IO;
using DotNetOpenMail;
using DotNetOpenMail.Utils;
using DotNetOpenMail.Encoding;
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests
{
[TestFixture]
public class EmailMessageInAlternateEncodings
{
SmtpServer _smtpserver=null;
private static readonly ILog log = LogManager.GetLogger(typeof(EmailMessageInAlternateEncodings));
public EmailMessageInAlternateEncodings()
{
}
[SetUp]
public void SetUp()
{
_smtpserver=TestAddressHelper.GetSmtpServer();
}
[TearDown]
public void TearDown() {}
#region TestJapaneseHtmlAndTextQPEncoding
[Test]
public void TestJapaneseHtmlAndTextQPEncoding()
{
//SmtpServer smtpserver=TestAddressHelper.GetSmtpServer();
System.Text.Encoding encoding=System.Text.Encoding.GetEncoding("Shift_JIS");
EmailAddress japanesefromaddress=new EmailAddress(TestAddressHelper.GetFromAddress().Email, "日本語", EncodingType.QuotedPrintable, encoding);
EmailAddress japanesetoaddress=new EmailAddress(TestAddressHelper.GetToAddress().Email, "日本語", EncodingType.QuotedPrintable, encoding);
EmailMessage emailmessage=new EmailMessage();
emailmessage.HeaderEncoding=DotNetOpenMail.Encoding.EncodingType.QuotedPrintable;
System.Text.Encoding jencoding=System.Text.Encoding.GetEncoding("iso-2022-jp");
//emailmessage.HeaderCharSet=System.Text.Encoding.GetEncoding("Shift_JIS");
emailmessage.HeaderCharSet=jencoding;
log.Debug("ENCODING IS "+jencoding.EncodingName);
log.Debug("IN HEADER:"+jencoding.HeaderName);
log.Debug("IN BODY:"+jencoding.BodyName);
log.Debug("CODE PAGE:"+jencoding.CodePage);
log.Debug("WebName:"+jencoding.WebName);
log.Debug("WINDOWS CODE PAGE:"+jencoding.WindowsCodePage);
emailmessage.FromAddress=japanesefromaddress;
emailmessage.AddToAddress(japanesetoaddress);
emailmessage.Subject="日本語 - Quoted Printable";
emailmessage.TextPart=new TextAttachment("東京、日本語");
//emailmessage.TextPart.CharSet+AD0AIg-Shift_JIS+ACIAOw-
emailmessage.TextPart.CharSet=jencoding;
emailmessage.TextPart.Encoding=DotNetOpenMail.Encoding.EncodingType.QuotedPrintable;
emailmessage.HtmlPart=new HtmlAttachment("<html><body>東京、日本語</body></html>");
//emailmessage.HtmlPart.CharSet+AD0AIg-Shift_JIS+ACIAOw-
emailmessage.HtmlPart.CharSet=jencoding;
emailmessage.HtmlPart.Encoding=DotNetOpenMail.Encoding.EncodingType.QuotedPrintable;
emailmessage.Send(_smtpserver);
String content=emailmessage.ToDataString();
StringReader sr=new StringReader(content);
log.Debug(content);
int i=0;
String line=null;
bool toHeaderEncoded=false;
bool fromHeaderEncoded=false;
bool subjectHeaderEncoded=false;
bool htmlEncoded=false;
bool textEncoded=false;
bool hasPlainText=false;
bool hasHtmlText=false;
while ((line=sr.ReadLine())!=null)
{
i++;
//log.Debug("FOUND +ACIAKw-line);
if (line.IndexOf("To: =?iso-2022-jp?Q?=93=FA=96{=8C=EA?= <"+japanesetoaddress.Email+">")==0)
{
toHeaderEncoded=true;
}
if (line.IndexOf("From") == 0)
{
String expectedfrom="From: =?iso-2022-jp?Q?=93=FA=96{=8C=EA?= <"+japanesefromaddress.Email+">";
if (line.IndexOf(expectedfrom)== 0)
{
fromHeaderEncoded=true;
}
}
if (line.IndexOf("Subject: =?iso-2022-jp?Q?=1B$BF|K\\8l=1B(B=20-=20Quoted=20Printable?=")==0)
{
subjectHeaderEncoded=true;
}
if (line.IndexOf("<html><body>=1B$BEl5~!\"F|K\\8l=1B(B</body></html>")==0)
{
//<html><body>=67=71=4E=AC=30=01=65=E5=67=2C=8A=9E</body></html>
htmlEncoded=true;
}
if (line.IndexOf("=1B$BEl5~!\"F|K\\8l=1B(B")==0)
{
textEncoded=true;
}
if (line.IndexOf("Content-Type: text/plain")==0)
{
hasPlainText=true;
}
if (line.IndexOf("Content-Type: text/html")==0)
{
hasHtmlText=true;
}
if (line.IndexOf("X-Mailer: DotNetOpenMail " + VersionInfo.GetInstance().ToString())==0)
{
//hasDefaultXMailerHeader=true;
}
if (line.IndexOf("X-MyHeader1: my header number one") == 0)
{
//hasCustomHeader1=true;
}
if (line.IndexOf("X-MyHeader2: my header number two") == 0)
{
//hasCustomHeader2=true;
}
// log.Debug("Line +ACIAKw-i+-": +ACIAKw-line);
}
Assert.IsTrue(toHeaderEncoded, "To Header not encoded");
Assert.IsTrue(fromHeaderEncoded, "From Header not encoded");
Assert.IsTrue(subjectHeaderEncoded, "Subject Header not encoded");
//Assert.IsTrue(hasSubjectHeader, "Missing Subject Header");
//Assert.IsTrue(hasMimeVersion, "Missing Mime Version header");
//Assert.IsTrue(hasMultipartAlternative, "Missing Mime Multipart/Alternative setting");
Assert.IsTrue(hasPlainText, "Missing Plain Text");
Assert.IsTrue(hasHtmlText, "Missing HTML");
Assert.IsTrue(htmlEncoded, "HTML Not encoded");
Assert.IsTrue(textEncoded, "Text Not encoded");
//Assert.IsTrue(hasDefaultXMailerHeader, "Missing X-Mailer Header");
//Assert.IsTrue(hasCustomHeader1, "Missing Custom Header 1");
//Assert.IsTrue(hasCustomHeader2, "Missing Custom Header 2");
//Assert.AreEqual(2, quotedPrintableParts, "Expected 2 quoted printable declarations, found +ACIAKw-quotedPrintableParts);
}
#endregion
#region TestJapaneseHtmlAndTextB64Encoding
[Test]
public void TestJapaneseHtmlAndTextB64Encoding()
{
//SmtpServer smtpserver=TestAddressHelper.GetSmtpServer();
System.Text.Encoding encoding=System.Text.Encoding.GetEncoding("Shift_JIS");
EmailAddress japanesefromaddress=new EmailAddress(TestAddressHelper.GetFromAddress().Email, "日本語", EncodingType.Base64, encoding);
EmailAddress japanesetoaddress=new EmailAddress(TestAddressHelper.GetToAddress().Email, "日本語", EncodingType.Base64, encoding);
EmailMessage emailmessage=new EmailMessage();
emailmessage.HeaderEncoding=DotNetOpenMail.Encoding.EncodingType.Base64;
emailmessage.HeaderCharSet=System.Text.Encoding.GetEncoding("Shift_JIS");
emailmessage.FromAddress=japanesefromaddress;
emailmessage.AddToAddress(japanesetoaddress);
emailmessage.Subject="日本語 - Base 64";
emailmessage.TextPart=new TextAttachment("東京、日本語");
emailmessage.TextPart.CharSet=System.Text.Encoding.GetEncoding("Shift_JIS");
emailmessage.TextPart.Encoding=DotNetOpenMail.Encoding.EncodingType.Base64;
emailmessage.HtmlPart=new HtmlAttachment("<html><body>東京、日本語</body></html>");
emailmessage.HtmlPart.CharSet=System.Text.Encoding.GetEncoding("Shift_JIS");
emailmessage.HtmlPart.Encoding=DotNetOpenMail.Encoding.EncodingType.Base64;
emailmessage.Send(_smtpserver);
String content=emailmessage.ToDataString();
StringReader sr=new StringReader(content);
log.Debug(content);
int i=0;
String line=null;
bool toHeaderEncoded=false;
bool fromHeaderEncoded=false;
bool subjectHeaderEncoded=false;
//bool htmlEncoded=false;
//bool textEncoded=false;
bool hasPlainText=false;
bool hasHtmlText=false;
while ((line=sr.ReadLine())!=null)
{
i++;
//log.Debug("FOUND +ACIAKw-line);
if (line.IndexOf("To: =?iso-2022-jp?B?k/qWe4zq?= <"+japanesetoaddress.Email+">")==0)
{
toHeaderEncoded=true;
}
if (line.IndexOf("From") == 0)
{
String expectedfrom="From: =?iso-2022-jp?B?k/qWe4zq?= <"+japanesefromaddress.Email+">";
if (line.IndexOf(expectedfrom)== 0)
{
fromHeaderEncoded=true;
}
}
if (line.IndexOf("Subject: =?iso-2022-jp?B?k/qWe4zqIC0gQmFzZSA2NA==?=")==0)
{
subjectHeaderEncoded=true;
}
if (line.IndexOf("Content-Type: multipart/alternative")==0)
{
//htmlEncoded=true;
}
if (line.IndexOf("Content-Type: text/html")==0)
{
hasHtmlText=true;
}
if (line.IndexOf("Content-Type: text/plain")==0)
{
hasPlainText=true;
}
if (line.IndexOf("X-Mailer: DotNetOpenMail " + VersionInfo.GetInstance().ToString())==0)
{
//hasDefaultXMailerHeader=true;
}
if (line.IndexOf("X-MyHeader1: my header number one") == 0)
{
//hasCustomHeader1=true;
}
if (line.IndexOf("X-MyHeader2: my header number two") == 0)
{
//hasCustomHeader2=true;
}
// log.Debug("Line +ACIAKw-i+-": +ACIAKw-line);
}
Assert.IsTrue(toHeaderEncoded, "To Header not encoded");
Assert.IsTrue(fromHeaderEncoded, "From Header not encoded");
Assert.IsTrue(subjectHeaderEncoded, "Subject Header not encoded");
//Assert.IsTrue(hasSubjectHeader, "Missing Subject Header");
//Assert.IsTrue(hasMimeVersion, "Missing Mime Version header");
//Assert.IsTrue(hasMultipartAlternative, "Missing Mime Multipart/Alternative setting");
Assert.IsTrue(hasPlainText, "Missing Plain Text");
Assert.IsTrue(hasHtmlText, "Missing HTML");
//Assert.IsTrue(htmlEncoded, "HTML Not encoded");
//Assert.IsTrue(textEncoded, "Text Not encoded");
//Assert.IsTrue(hasDefaultXMailerHeader, "Missing X-Mailer Header");
//Assert.IsTrue(hasCustomHeader1, "Missing Custom Header 1");
//Assert.IsTrue(hasCustomHeader2, "Missing Custom Header 2");
//Assert.AreEqual(2, quotedPrintableParts, "Expected 2 quoted printable declarations, found +ACIAKw-quotedPrintableParts);
}
#endregion
}
}
@@ -0,0 +1,590 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.IO;
using DotNetOpenMail;
using DotNetOpenMail.Utils;
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests {
[TestFixture]
public class EmailMessageTests {
SmtpServer _smtpserver=null;
private static readonly ILog log = LogManager.GetLogger(typeof(EmailMessageTests));
public EmailMessageTests() {
}
[SetUp]
public void SetUp()
{
_smtpserver=TestAddressHelper.GetSmtpServer();
}
[TearDown]
public void TearDown() {}
#region TestHtmlAndText
[Test]
public void TestHtmlAndText()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="EmailMessageTests Test HTML and Text";
emailmessage.TextPart=new TextAttachment("This\r\nis the\r\ntext\r\npart.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br>\r\nis the<br>\r\n<strong>HTML</strong><br>\r\npart.</body></html>");
emailmessage.AddCustomHeader("X-MyHeader1", "my header number one");
emailmessage.AddCustomHeader("X-MyHeader2", "my header number two");
emailmessage.Send(_smtpserver);
String content=emailmessage.ToDataString();
StringReader sr=new StringReader(content);
log.Debug(content);
int i=0;
String line=null;
bool hasToHeader=false;
bool hasFromHeader=false;
bool hasSubjectHeader=false;
bool hasMimeVersion=false;
bool hasMultipartAlternative=false;
bool hasPlainText=false;
bool hasHtmlText=false;
bool hasDefaultXMailerHeader=false;
bool hasCustomHeader1=false;
bool hasCustomHeader2=false;
int quotedPrintableParts=0;
String expectedToAddress=TestAddressHelper.GetToAddress().Name+" <"+TestAddressHelper.GetToAddress().Email+">";
while ((line=sr.ReadLine())!=null)
{
i++;
if (line.IndexOf("To: "+expectedToAddress)==0)
{
hasToHeader=true;
}
if (line.IndexOf("From: "+emailmessage.FromAddress.ToString())==0)
{
hasFromHeader=true;
}
if (line.IndexOf("Subject: "+emailmessage.Subject)==0)
{
hasSubjectHeader=true;
}
if (line.IndexOf("MIME-Version: 1.0")==0)
{
hasMimeVersion=true;
}
if (line.IndexOf("Content-Type: multipart/alternative;")==0)
{
hasMultipartAlternative=true;
}
if (line.IndexOf("Content-Type: text/html")==0)
{
hasHtmlText=true;
}
if (line.IndexOf("Content-Type: text/plain")==0)
{
hasPlainText=true;
}
if (line.IndexOf("Content-Transfer-Encoding: quoted-printable")==0)
{
quotedPrintableParts++;
}
if (line.IndexOf("X-Mailer: DotNetOpenMail") == 0)
{
hasDefaultXMailerHeader=true;
}
if (line.IndexOf("X-MyHeader1: my header number one") == 0)
{
hasCustomHeader1=true;
}
if (line.IndexOf("X-MyHeader2: my header number two") == 0)
{
hasCustomHeader2=true;
}
// log.Debug("Line "+i+": "+line);
}
Assert.IsTrue(hasToHeader, "Missing TO Header");
Assert.IsTrue(hasFromHeader, "Missing FROM Header");
Assert.IsTrue(hasSubjectHeader, "Missing Subject Header");
Assert.IsTrue(hasMimeVersion, "Missing Mime Version header");
Assert.IsTrue(hasMultipartAlternative, "Missing Mime Multipart/Alternative setting");
Assert.IsTrue(hasPlainText, "Missing Plain Text");
Assert.IsTrue(hasHtmlText, "Missing HTML");
Assert.IsTrue(hasDefaultXMailerHeader, "Missing X-Mailer Header");
Assert.IsTrue(hasCustomHeader1, "Missing Custom Header 1");
Assert.IsTrue(hasCustomHeader2, "Missing Custom Header 2");
Assert.AreEqual(2, quotedPrintableParts, "Expected 2 quoted printable declarations, found "+quotedPrintableParts);
}
#endregion
#region TestGraphicAttachment
[Test]
public void TestGraphicAttachment()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="EmailMessageTests Test HTML+Text+Graphic";
emailmessage.TextPart=new TextAttachment("This\r\nis the\r\ntext\r\npart.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br>\r\nis the<br>\r\n<strong>HTML</strong><br>\r\npart.</body></html>");
FileInfo fileinfo=new FileInfo(@"..\..\TestFiles\grover.jpg");
Assert.IsTrue(fileinfo.Exists);
FileAttachment fileattachment=new FileAttachment(fileinfo);
fileattachment.ContentType="image/jpeg";
emailmessage.AddMixedAttachment(fileattachment);
//emailmessage.Send(_smtpserver);
//log.Debug("MESSAGE: "+emailmessage.ToDataString());
String content=emailmessage.ToDataString();
StringReader sr=new StringReader(content);
int i=0;
String line=null;
bool hasMimeVersion=false;
bool hasMixedHeader=false;
bool mixedHeaderComesFirst=false;
bool hasMultipartAlternative=false;
bool hasPlainText=false;
bool hasHtmlText=false;
bool hasAttachment=false;
bool hasRelatedHeader=false;
int quotedPrintableParts=0;
String expectedToAddress=TestAddressHelper.GetToAddress().Name+" <"+TestAddressHelper.GetToAddress().Email+">";
//log.Debug("To Address is "+expectedToAddress);
while ((line=sr.ReadLine())!=null)
{
i++;
if (line.IndexOf("Content-Type: multipart/mixed")==0)
{
hasMixedHeader=true;
if (!hasMultipartAlternative)
{
mixedHeaderComesFirst=true;
}
}
if (line.IndexOf("MIME-Version: 1.0")==0)
{
hasMimeVersion=true;
}
if (line.IndexOf("Content-Type: multipart/alternative;")==0)
{
hasMultipartAlternative=true;
}
if (line.IndexOf("Content-Type: text/html")==0)
{
hasHtmlText=true;
}
if (line.IndexOf("Content-Type: text/plain")==0)
{
hasPlainText=true;
}
if (line.IndexOf("Content-Type: image/jpeg")==0)
{
hasAttachment=true;
}
if (line.IndexOf("Content-Transfer-Encoding: quoted-printable")==0)
{
quotedPrintableParts++;
}
if (line.IndexOf("/9j/4AAQSkZJRgABAQEASABIAAD/")==0)
{
hasAttachment=true;
}
if (line.IndexOf("Content-Type: multipart/related")>=0)
{
hasRelatedHeader=true;
}
//log.Debug("Line "+i+": "+line);
}
Assert.IsTrue(hasMixedHeader, "Missing multipart/mixed header");
Assert.IsTrue(hasMimeVersion, "Missing Mime Version header");
Assert.IsTrue(mixedHeaderComesFirst, "The mixed header should come first");
Assert.IsTrue(hasMultipartAlternative, "Missing Mime Multipart/Alternative setting");
Assert.IsTrue(hasPlainText, "Missing Plain Text");
Assert.IsTrue(hasHtmlText, "Missing HTML");
Assert.IsTrue(hasAttachment, "Missing the base64 Attachment");
Assert.IsFalse(hasRelatedHeader, "Should not have a related header.");
Assert.AreEqual(2, quotedPrintableParts, "Expected 2 quoted printable declarations, found "+quotedPrintableParts);
}
#endregion
#region TestRelatedAndMixedAttachments
[Test]
public void TestRelatedAndMixedAttachments()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="EmailMessageTests Test HTML+Text+Graphic";
emailmessage.TextPart=new TextAttachment("This\r\nis the\r\ntext\r\npart.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br> \r\nis the<br><img src=\"cid:mycontentid@rhombus\"> \r\n<strong>HTML</strong><br>\r\npart.</body></html>");
FileInfo relatedfileinfo=new FileInfo(@"..\..\TestFiles\grover.jpg");
FileInfo mixedfileinfo=new FileInfo(@"..\..\TestFiles\groverUpsideDown.jpg");
Assert.IsTrue(relatedfileinfo.Exists);
Assert.IsTrue(mixedfileinfo.Exists);
FileAttachment relatedfileattachment=new FileAttachment(relatedfileinfo,"mycontentid@rhombus");
relatedfileattachment.ContentType="image/jpeg";
FileAttachment mixedfileattachment=new FileAttachment(mixedfileinfo);
mixedfileattachment.ContentType="image/jpeg";
emailmessage.AddRelatedAttachment(relatedfileattachment);
emailmessage.AddMixedAttachment(mixedfileattachment);
//emailmessage.Send(_smtpserver);
String content=emailmessage.ToDataString();
StringReader sr=new StringReader(content);
int i=0;
String line=null;
bool hasMimeVersion=false;
bool hasMixedHeader=false;
bool mixedHeaderComesFirst=false;
bool hasMultipartAlternative=false;
bool hasPlainText=false;
bool hasHtmlText=false;
bool hasAttachment=false;
bool hasRelatedHeader=false;
int quotedPrintableParts=0;
String expectedToAddress=TestAddressHelper.GetToAddress().Name+" <"+TestAddressHelper.GetToAddress().Email+">";
//log.Debug("To Address is "+expectedToAddress);
while ((line=sr.ReadLine())!=null)
{
i++;
if (line.IndexOf("Content-Type: multipart/mixed")==0)
{
hasMixedHeader=true;
if (!hasMultipartAlternative && !hasRelatedHeader)
{
mixedHeaderComesFirst=true;
}
}
if (line.IndexOf("MIME-Version: 1.0")==0)
{
hasMimeVersion=true;
}
if (line.IndexOf("Content-Type: multipart/alternative;")==0)
{
hasMultipartAlternative=true;
}
if (line.IndexOf("Content-Type: text/html")==0)
{
hasHtmlText=true;
}
if (line.IndexOf("Content-Type: text/plain")==0)
{
hasPlainText=true;
}
if (line.IndexOf("Content-Type: image/jpeg")==0)
{
hasAttachment=true;
}
if (line.IndexOf("Content-Transfer-Encoding: quoted-printable")==0)
{
quotedPrintableParts++;
}
if (line.IndexOf("/9j/4AAQSkZJRgABAQEASABIAAD/")==0)
{
hasAttachment=true;
}
if (line.IndexOf("Content-Type: multipart/related")>=0)
{
hasRelatedHeader=true;
}
//log.Debug("Line "+i+": "+line);
}
Assert.IsTrue(hasMixedHeader, "Missing multipart/mixed header");
Assert.IsTrue(hasMimeVersion, "Missing Mime Version header");
Assert.IsTrue(mixedHeaderComesFirst, "The mixed header should come first");
Assert.IsTrue(hasMultipartAlternative, "Missing Mime Multipart/Alternative setting");
Assert.IsTrue(hasPlainText, "Missing Plain Text");
Assert.IsTrue(hasHtmlText, "Missing HTML");
Assert.IsTrue(hasAttachment, "Missing the base64 Attachment");
Assert.IsTrue(hasRelatedHeader, "Missing the related header.");
Assert.AreEqual(2, quotedPrintableParts, "Expected 2 quoted printable declarations, found "+quotedPrintableParts);
}
#endregion
#region TestRelatedAttachments
[Test]
public void TestRelatedAttachments()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="EmailMessageTests Test Related Graphic";
emailmessage.TextPart=new TextAttachment("This\r\nis the\r\ntext\r\npart.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br>\r\nis the<br><img src=\"cid:mycontentid\">\r\n<strong>HTML</strong><br>\r\npart.</body></html>");
FileInfo relatedfileinfo=new FileInfo(@"..\..\TestFiles\grover.jpg");
Assert.IsTrue(relatedfileinfo.Exists);
FileAttachment relatedfileattachment=new FileAttachment(relatedfileinfo,"mycontentid");
relatedfileattachment.ContentType="image/jpeg";
emailmessage.AddRelatedAttachment(relatedfileattachment);
//emailmessage.Send(_smtpserver);
String content=emailmessage.ToDataString();
StringReader sr=new StringReader(content);
int i=0;
String line=null;
bool hasMimeVersion=false;
bool hasMixedHeader=false;
bool relatedHeaderComesFirst=false;
bool hasMultipartAlternative=false;
bool hasPlainText=false;
bool hasHtmlText=false;
bool hasAttachment=false;
bool hasRelatedHeader=false;
int quotedPrintableParts=0;
String expectedToAddress=TestAddressHelper.GetToAddress().Name+" <"+TestAddressHelper.GetToAddress().Email+">";
//log.Debug("To Address is "+expectedToAddress);
while ((line=sr.ReadLine())!=null)
{
i++;
if (line.IndexOf("Content-Type: multipart/mixed")==0)
{
hasMixedHeader=true;
}
if (line.IndexOf("MIME-Version: 1.0")==0)
{
hasMimeVersion=true;
}
if (line.IndexOf("Content-Type: multipart/alternative;")==0)
{
hasMultipartAlternative=true;
}
if (line.IndexOf("Content-Type: text/html")==0)
{
hasHtmlText=true;
}
if (line.IndexOf("Content-Type: text/plain")==0)
{
hasPlainText=true;
}
if (line.IndexOf("Content-Type: image/jpeg")==0)
{
hasAttachment=true;
}
if (line.IndexOf("Content-Transfer-Encoding: quoted-printable")==0)
{
quotedPrintableParts++;
}
if (line.IndexOf("/9j/4AAQSkZJRgABAQEASABIAAD/")==0)
{
hasAttachment=true;
}
if (line.IndexOf("Content-Type: multipart/related")>=0)
{
hasRelatedHeader=true;
if (!hasMultipartAlternative && !hasMixedHeader)
{
relatedHeaderComesFirst=true;
}
}
//log.Debug("Line "+i+": "+line);
}
Assert.IsFalse(hasMixedHeader, "Should not have a multipart/mixed header");
Assert.IsTrue(hasMimeVersion, "Missing Mime Version header");
Assert.IsTrue(relatedHeaderComesFirst, "The related header should come first");
Assert.IsTrue(hasMultipartAlternative, "Missing Mime Multipart/Alternative setting");
Assert.IsTrue(hasPlainText, "Missing Plain Text");
Assert.IsTrue(hasHtmlText, "Missing HTML");
Assert.IsTrue(hasAttachment, "Missing the base64 Attachment");
Assert.IsTrue(hasRelatedHeader, "Missing the related header.");
Assert.AreEqual(2, quotedPrintableParts, "Expected 2 quoted printable declarations, found "+quotedPrintableParts);
}
#endregion
#region TestHeaders
[Test]
public void TestHeaders()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.AddCcAddress(TestAddressHelper.GetToAddress());
emailmessage.AddCcAddress(TestAddressHelper.GetToAddress());
emailmessage.AddBccAddress(TestAddressHelper.GetToAddress());
emailmessage.AddBccAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="Test Headers";
emailmessage.XMailer="NUnit Test Mailer";
emailmessage.TextPart=new TextAttachment("This\r\nis the\r\ntext\r\npart.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br>\r\nis the<br>\r\n<strong>HTML</strong><br>\r\npart.</body></html>");
String content=emailmessage.ToDataString();
StringReader sr=new StringReader(content);
int i=0;
String line=null;
bool hasToHeader=false;
bool hasFromHeader=false;
bool hasSubjectHeader=false;
bool hasBccHeader=false;
bool hasCcHeader=false;
bool hasXMailerHeader=false;
String expectedToAddress=TestAddressHelper.GetToAddress().Name+" <"+TestAddressHelper.GetToAddress().Email+">";
while ((line=sr.ReadLine())!=null)
{
i++;
if (line.IndexOf("To: "+expectedToAddress+", "+expectedToAddress)==0)
{
hasToHeader=true;
}
if (line.IndexOf("Cc: "+expectedToAddress+", "+expectedToAddress)==0)
{
hasCcHeader=true;
}
if (line.IndexOf("Bcc: "+expectedToAddress+", "+expectedToAddress)==0)
{
hasBccHeader=true;
}
if (line.IndexOf("From: "+emailmessage.FromAddress.ToString())==0)
{
hasFromHeader=true;
}
if (line.IndexOf("Subject: "+emailmessage.Subject)==0)
{
hasSubjectHeader=true;
}
if (line.IndexOf("X-Mailer: NUnit Test Mailer")==0)
{
hasXMailerHeader=true;
}
}
Assert.IsTrue(hasToHeader, "Missing TO Header");
Assert.IsTrue(hasFromHeader, "Missing FROM Header");
Assert.IsTrue(hasSubjectHeader, "Missing Subject Header");
Assert.IsTrue(hasCcHeader, "Missing Cc Header");
Assert.IsFalse(hasBccHeader, "Bcc Header Shouldn't appear");
Assert.IsTrue(hasXMailerHeader, "Missing XMailer Header");
//emailmessage.Send(_smtpserver);
}
#endregion
#region TestLongSubjectEncoded
[Test]
public void TestLongSubjectEncoded()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.AddCcAddress(TestAddressHelper.GetToAddress());
emailmessage.AddBccAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="Join our Group's Fundraising Efforts é test test test Gulf Little League";
emailmessage.HeaderEncoding=DotNetOpenMail.Encoding.EncodingType.QuotedPrintable;
emailmessage.XMailer="NUnit Test Mailer";
emailmessage.TextPart=new TextAttachment("This\r\nis the\r\ntext\r\npart.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br>\r\nis the<br>\r\n<strong>HTML</strong><br>\r\npart.</body></html>");
String content=emailmessage.ToDataString();
emailmessage.Send(_smtpserver);
}
#endregion
#region TestExtraHeader
[Test]
public void TestExtraHeader()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.AddCcAddress(TestAddressHelper.GetToAddress());
emailmessage.AddBccAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="Extra Header";
emailmessage.HeaderEncoding=DotNetOpenMail.Encoding.EncodingType.QuotedPrintable;
emailmessage.XMailer="NUnit Test Mailer";
emailmessage.AddCustomHeader("MyHeader", "Value");
emailmessage.TextPart=new TextAttachment("This\r\nis the\r\ntext\r\npart.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br>\r\nis the<br>\r\n<strong>HTML</strong><br>\r\npart.</body></html>");
String content=emailmessage.ToDataString();
emailmessage.Send(_smtpserver);
}
#endregion
#region TestMissingFrom
[Test]
public void TestMissingFrom()
{
EmailMessage emailmessage=new EmailMessage();
try
{
emailmessage.Send(_smtpserver);
Assert.Fail("This should throw an error if no from address");
}
catch (MailException ex)
{
log.Debug("Ignoring exception "+ex.Message);
}
}
#endregion
}
}
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.IO;
using DotNetOpenMail.Encoding;
using log4net;
using NUnit.Framework;
namespace DotNetOpenMailTests.Encoding
{
[TestFixture]
public class Base64EncoderTests
{
private static readonly ILog log = LogManager.GetLogger(typeof(Base64EncoderTests));
public Base64EncoderTests()
{
}
[SetUp]
public void SetUp()
{
}
[TearDown]
public void TearDown()
{
}
[Test]
public void SimpleTest()
{
String setofchars=""+(char)0x01 +(char)0x02+(char)0x03;
Base64Encoder base64encoder=Base64Encoder.GetInstance();
StringReader sr=new StringReader(setofchars);
StringBuilder sb=new StringBuilder();
StringWriter sw=new StringWriter(sb);
base64encoder.Encode(sr, sw, System.Text.Encoding.GetEncoding("iso-8859-1"));
log.Debug(sb.ToString());
Assert.AreEqual("AQID", sb.ToString());
}
[Test]
public void LineLengthTest()
{
String line="12345678901234567890123456789012345678901234567890123456789012345678901234567890";
String expectedresult="MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3\r\nODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTA=";
Base64Encoder base64=Base64Encoder.GetInstance();
StringReader sr=new StringReader(line);
StringBuilder sb=new StringBuilder();
StringWriter sw=new StringWriter(sb);
base64.Encode(sr, sw, System.Text.Encoding.GetEncoding("iso-8859-1"));
log.Debug(sb.ToString());
Assert.AreEqual(expectedresult, sb.ToString());
Assert.AreEqual(expectedresult, base64.EncodeString(line, System.Text.Encoding.GetEncoding("iso-8859-1")));
}
[Test]
public void HeaderEncodingTest()
{
Base64Encoder base64=Base64Encoder.GetInstance();
String result=base64.EncodeHeaderString("Test", "helloøæô", System.Text.Encoding.GetEncoding("iso-8859-1"), false);
log.Debug("RESULT IS "+result);
Assert.AreEqual("=?iso-8859-1?B?aGVsbG/45vQ=?=", result);
}
}
}
@@ -0,0 +1,132 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.IO;
using DotNetOpenMail;
using DotNetOpenMail.Encoding;
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests.Encoding {
[TestFixture]
public class EightBitEncoderTests {
private static readonly ILog log = LogManager.GetLogger(typeof(EightBitEncoderTests));
public EightBitEncoderTests() {
}
[SetUp]
public void SetUp() {}
[TearDown]
public void TearDown() {}
[Test]
public void SimpleTest()
{
// this tests that the 8bit encoder does nothing
String setofchars=Get256Chars();
EightBitEncoder eightbitencoder=EightBitEncoder.GetInstance();
StringReader sr=new StringReader(setofchars);
StringBuilder sb=new StringBuilder();
StringWriter sw=new StringWriter(sb);
eightbitencoder.Encode(sr, sw, System.Text.Encoding.GetEncoding("iso-8859-1"));
Assert.AreEqual(setofchars, sb.ToString());
}
private String Get256Chars()
{
StringBuilder sb=new StringBuilder();
for (int i=0; i<256; i++)
{
sb.Append((char) i);
}
return sb.ToString();
}
#region TestFor8BitHeader
[Test]
public void TestFor8BitHeader()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.HeaderCharSet=System.Text.ASCIIEncoding.ASCII;
emailmessage.HeaderEncoding=DotNetOpenMail.Encoding.EncodingType.EightBit;
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="EmailMessageTests Test HTML and Text";
emailmessage.TextPart=new TextAttachment("This\r\nis the\r\ntext\r\npart.");
emailmessage.TextPart.CharSet=System.Text.ASCIIEncoding.ASCII;
emailmessage.TextPart.Encoding=DotNetOpenMail.Encoding.EncodingType.EightBit;
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br>\r\nis the<br>\r\n<strong>HTML</strong><br>\r\npart.</body></html>");
emailmessage.HtmlPart.CharSet=System.Text.ASCIIEncoding.ASCII;
emailmessage.HtmlPart.Encoding=DotNetOpenMail.Encoding.EncodingType.EightBit;
//emailmessage.Send(_smtpserver);
String content=emailmessage.ToDataString();
StringReader sr=new StringReader(content);
log.Debug(content);
int i=0;
String line=null;
String expectedToAddress=TestAddressHelper.GetToAddress().Name+" <"+TestAddressHelper.GetToAddress().Email+">";
int has8Bit=0;
int hasUSASCII=0;
while ((line=sr.ReadLine())!=null)
{
i++;
if (line.IndexOf("Content-Transfer-Encoding: 8bit")==0)
{
has8Bit++;
}
if (line.IndexOf("charset=\"us-ascii\"")>0)
{
hasUSASCII++;
}
log.Debug("Line "+i+": "+line);
}
Assert.AreEqual(2, has8Bit, "Not enough 8bit lines");
Assert.AreEqual(2, hasUSASCII, "Not enough us-ascii lines");
}
#endregion
}
}
@@ -0,0 +1,170 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.IO;
using DotNetOpenMail.Encoding;
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests.Encoding {
[TestFixture]
public class QPEncoderTests {
private static readonly ILog log = LogManager.GetLogger(typeof(QPEncoderTests));
public QPEncoderTests() {
}
[SetUp]
public void SetUp() {}
[TearDown]
public void TearDown() {}
[Test]
public void SimpleTest() {
//String setofchars=Get256Chars();
String setofchars=""+(char)0x01 +(char)0x02;
QPEncoder qpencoder=QPEncoder.GetInstance();
StringReader sr=new StringReader(setofchars);
StringBuilder sb=new StringBuilder();
StringWriter sw=new StringWriter(sb);
qpencoder.Encode(sr, sw, System.Text.Encoding.GetEncoding("iso-8859-1"));
Assert.AreEqual("=01=02", sb.ToString());
}
[Test]
public void LineLengthTest()
{
String line="12345678901234567890123456789012345678901234567890123456789012345678901234567890";
String expectedresult="1234567890123456789012345678901234567890123456789012345678901234567890123456=\r\n7890";
QPEncoder qpencoder=QPEncoder.GetInstance();
StringReader sr=new StringReader(line);
StringBuilder sb=new StringBuilder();
StringWriter sw=new StringWriter(sb);
qpencoder.Encode(sr, sw, System.Text.Encoding.GetEncoding("iso-8859-1"));
Assert.AreEqual(expectedresult, sb.ToString());
Assert.AreEqual(expectedresult, qpencoder.EncodeString(line, System.Text.Encoding.GetEncoding("iso-8859-1")));
}
[Test]
public void EndOfLineSpacesTest()
{
QPEncoder qpencoder=QPEncoder.GetInstance();
Assert.AreEqual("123 456 7890=20=20=20=20=20",qpencoder.EncodeString("123 456 7890 ", System.Text.Encoding.GetEncoding("iso-8859-1")));
Assert.AreEqual("=20=20=20=20=20",qpencoder.EncodeString(" ", System.Text.Encoding.GetEncoding("iso-8859-1")));
Assert.AreEqual("123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456=\r\n7890=20=20=20",qpencoder.EncodeString("123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 ", System.Text.Encoding.GetEncoding("iso-8859-1")));
Assert.AreEqual("123456789 123456789 123456789 123456789 123456789 123456789 123456789=\r\n=20=20=20=20=20=20=20=20=20=20=20",qpencoder.EncodeString("123456789 123456789 123456789 123456789 123456789 123456789 123456789 ", System.Text.Encoding.GetEncoding("iso-8859-1")));
Assert.AreEqual("123456789 123456789 123456789 123456789 123456789 123456789 123456789=\r\n=09=09=09=09=09=09=09=09=09=09=09",qpencoder.EncodeString("123456789 123456789 123456789 123456789 123456789 123456789 123456789 ", System.Text.Encoding.GetEncoding("iso-8859-1")));
}
[Test]
public void UnixAndMacCRLF()
{
QPEncoder qpencoder=QPEncoder.GetInstance();
Assert.AreEqual("123\r\n456\r\n789",qpencoder.EncodeString("123\r456\r789\r", System.Text.Encoding.GetEncoding("iso-8859-1")));
Assert.AreEqual("123\r\n456\r\n789",qpencoder.EncodeString("123\n456\n789\n", System.Text.Encoding.GetEncoding("iso-8859-1")));
}
[Test]
public void Test256Chars()
{
QPEncoder qpencoder=QPEncoder.GetInstance();
String expected="=00=01=02=03=04=05=06=07=08=09\r\n"+
"=0B=0C\r\n"+
"=0E=0F=10=11=12=13=14=15=16=17=18=19=1A=1B=1C=1D=1E=1F !\"#$%&'()*+,-./012345=\r\n"+
"6789:;<=3D>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~=\r\n"+
"=7F=80=81=82=83=84=85=86=87=88=89=8A=8B=8C=8D=8E=8F=90=91=92=93=94=95=96=97=98=\r\n"+
"=99=9A=9B=9C=9D=9E=9F=A0=A1=A2=A3=A4=A5=A6=A7=A8=A9=AA=AB=AC=AD=AE=AF=B0=B1=B2=\r\n"+
"=B3=B4=B5=B6=B7=B8=B9=BA=BB=BC=BD=BE=BF=C0=C1=C2=C3=C4=C5=C6=C7=C8=C9=CA=CB=CC=\r\n"+
"=CD=CE=CF=D0=D1=D2=D3=D4=D5=D6=D7=D8=D9=DA=DB=DC=DD=DE=DF=E0=E1=E2=E3=E4=E5=E6=\r\n"+
"=E7=E8=E9=EA=EB=EC=ED=EE=EF=F0=F1=F2=F3=F4=F5=F6=F7=F8=F9=FA=FB=FC=FD=FE=FF";
Assert.AreEqual(256,Get256Chars().Length);
Assert.AreEqual(expected, qpencoder.EncodeString(Get256Chars(), System.Text.Encoding.GetEncoding("iso-8859-1")));
}
private String Get256Chars()
{
StringBuilder sb=new StringBuilder();
for (int i=0; i<256; i++)
{
sb.Append((char) i);
}
return sb.ToString();
}
[Test]
public void HeaderEncodingTest()
{
QPEncoder qpencoder=QPEncoder.GetInstance();
Assert.AreEqual("=?iso-8859-1?Q?hello=F8=E6=F4?=", qpencoder.EncodeHeaderString("Test", "helloøæô", System.Text.Encoding.GetEncoding("iso-8859-1"), false));
Assert.AreEqual("=?iso-8859-1?Q?hello=20there=20=F8=E6=F4?=", qpencoder.EncodeHeaderString("Test", "hello there øæô", System.Text.Encoding.GetEncoding("iso-8859-1"), false));
Assert.AreEqual("hello there", qpencoder.EncodeHeaderString("Test", "hello there", System.Text.Encoding.GetEncoding("iso-8859-1"), false));
Assert.AreEqual("=?iso-8859-1?Q?hello=20there?=", qpencoder.EncodeHeaderString("Test", "hello there", System.Text.Encoding.GetEncoding("iso-8859-1"), true));
Assert.AreEqual("=?iso-8859-1?Q?TSpecials=20Equals=20=3D=20QuestionMark=3FEnd?=", qpencoder.EncodeHeaderString("Test", "TSpecials Equals = QuestionMark?End", System.Text.Encoding.GetEncoding("iso-8859-1"), true));
Assert.AreEqual("=?iso-8859-1?Q?en=20to,=20sn=F8r=20min=20sko,=20tre=20fire=20kom=20E?=\r\n\t=?iso-8859-1?Q?lvire,=20fem=20seks=20tegn=20en=20heks,=20sju=20=E5tte?=\r\n\t=?iso-8859-1?Q?=20ris=20til=20en=20rotte?=", qpencoder.EncodeHeaderString("Test", "en to, snør min sko, tre fire kom Elvire, fem seks tegn en heks, sju åtte ris til en rotte",
System.Text.Encoding.GetEncoding("iso-8859-1"), true));
Assert.AreEqual("=?koi8-r?Q?n=CE=C5=D3=CB=CF=CC=D8=CB=CF=20=D3=D4=D2=CF=CB=20=D0=CF?=\r\n\t=?koi8-r?Q?=20=D2=D5=D3=D3=CB=C9=3F?=", qpencoder.EncodeHeaderString("Test", "nнесколько строк по русски?", System.Text.Encoding.GetEncoding("koi8-r"), true));
}
/*
[Test]
public void KOI8_QP_Tests()
{
EmailMessage msg = new EmailMessage();
msg.FromAddress = new EmailAddress("pietrovich@talk.test","pietrovich");
msg.ToAddresses.Add(new EmailAddress("pietrovich@talk.test","pietrovich"));
msg.Subject = "ошибочка?";
msg.HeaderCharSet = Encoding.GetEncoding("windows-1251");
TextAttachment ta = new TextAttachment("\r\nнесколько строк по русски");
ta.CharSet = Encoding.GetEncoding("windows-1251");
msg.TextPart = ta;
Console.WriteLine(msg.ToDataString());
}
*/
}
}
@@ -0,0 +1,132 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.IO;
using DotNetOpenMail;
using DotNetOpenMail.Encoding;
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests.Encoding {
[TestFixture]
public class SevenBitEncoderTests {
private static readonly ILog log = LogManager.GetLogger(typeof(SevenBitEncoderTests));
public SevenBitEncoderTests() {
}
[SetUp]
public void SetUp() {}
[TearDown]
public void TearDown() {}
[Test]
public void SimpleTest()
{
// this tests that the 8bit encoder does nothing
String setofchars=Get256Chars();
SevenBitEncoder sevenbitencoder=SevenBitEncoder.GetInstance();
StringReader sr=new StringReader(setofchars);
StringBuilder sb=new StringBuilder();
StringWriter sw=new StringWriter(sb);
sevenbitencoder.Encode(sr, sw, System.Text.Encoding.GetEncoding("iso-8859-1"));
Assert.AreEqual(setofchars, sb.ToString());
}
private String Get256Chars()
{
StringBuilder sb=new StringBuilder();
for (int i=0; i<256; i++)
{
sb.Append((char) i);
}
return sb.ToString();
}
#region TestFor7BitHeader
[Test]
public void TestFor7BitHeader()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.HeaderCharSet=System.Text.ASCIIEncoding.ASCII;
emailmessage.HeaderEncoding=DotNetOpenMail.Encoding.EncodingType.SevenBit;
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="EmailMessageTests Test HTML and Text";
emailmessage.TextPart=new TextAttachment("This\r\nis the\r\ntext\r\npart.");
emailmessage.TextPart.CharSet=System.Text.ASCIIEncoding.ASCII;
emailmessage.TextPart.Encoding=DotNetOpenMail.Encoding.EncodingType.SevenBit;
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br>\r\nis the<br>\r\n<strong>HTML</strong><br>\r\npart.</body></html>");
emailmessage.HtmlPart.CharSet=System.Text.ASCIIEncoding.ASCII;
emailmessage.HtmlPart.Encoding=DotNetOpenMail.Encoding.EncodingType.SevenBit;
//emailmessage.Send(_smtpserver);
String content=emailmessage.ToDataString();
StringReader sr=new StringReader(content);
//log.Debug(content);
int i=0;
String line=null;
String expectedToAddress=TestAddressHelper.GetToAddress().Name+" <"+TestAddressHelper.GetToAddress().Email+">";
int has7Bit=0;
int hasUSASCII=0;
while ((line=sr.ReadLine())!=null)
{
i++;
if (line.IndexOf("Content-Transfer-Encoding: 7bit")==0)
{
has7Bit++;
}
if (line.IndexOf("charset=\"us-ascii\"")>0)
{
hasUSASCII++;
}
//log.Debug("Line "+i+": "+line);
}
Assert.AreEqual(2, has7Bit, "Not enough 7bit lines");
Assert.AreEqual(2, hasUSASCII, "Not enough us-ascii lines");
}
#endregion
}
}
@@ -0,0 +1,122 @@
using System;
using System.IO;
using DotNetOpenMail; // change to tested dir
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests {
[TestFixture]
public class ExampleTests {
private static readonly ILog log = LogManager.GetLogger(typeof(ExampleTests));
public ExampleTests() {
}
[SetUp]
public void SetUp() {}
[TearDown]
public void TearDown() {}
[Test]
public void TestOne()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="Missed you";
emailmessage.TextPart=new TextAttachment("Just checking where "+
"you were last night.\r\nSend me a note!\r\n\r\n-Charles");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>"+
"<p>Just checking up on where you were last night.</p>\r\n"+
"<p>Send me a note!</p>\r\n\r\n"+
"<p>-Charles</p></body></html>");
SmtpServer smtpserver=TestAddressHelper.GetSmtpServer();
//smtpserver.CaptureSmtpConversation=true;
try
{
emailmessage.Send(smtpserver);
}
finally
{
//log.Debug(smtpserver.GetSmtpConversation());
//Assert.IsNotNull(smtpserver.GetSmtpConversation());
//smtpserver.CaptureSmtpConversation=false;
}
}
[Test]
public void TestTwo()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="A photo of hawthornes";
emailmessage.TextPart=new TextAttachment("This photo requires a better email reader.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>"+
"<p>Note to self: look at this photo again in 30 years.</p>"+
"<p><img src=\"cid:hawthornes\" alt=\"Hawthorne bush\"/></p>"+
"<p>-Marcel</p>");
FileInfo relatedfileinfo=new FileInfo(@"..\..\TestFiles\grover.jpg");
FileAttachment relatedfileattachment=new FileAttachment(relatedfileinfo,"hawthornes");
relatedfileattachment.ContentType="image/jpeg";
emailmessage.AddRelatedAttachment(relatedfileattachment);
SmtpServer smtpserver=TestAddressHelper.GetSmtpServer();
emailmessage.Send(smtpserver);
//Assert.IsNull(smtpserver.GetSmtpConversation());
}
[Test]
public void TestThree()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="Something has come up";
emailmessage.TextPart=new TextAttachment("I regret that something has "+
"come up unexpectedly,\r\n"+
"and I must postpone our meeting.\r\n\r\n"+
"Please read the 20 pages of my thoughts on this in the attached\r\n"+
"PDF file.\r\n\r\n-Marcel");
emailmessage.HtmlPart=new HtmlAttachment("<p>I regret that something "+
"has come up unexpectedly,\r\n"+
"and I must postpone our meeting.</p>\r\n"+
"<p>Please read the 20 pages of my thoughts on this in the attached\r\n"+
"PDF file.</p>\r\n<p>-Marcel</p>");
FileAttachment fileattachment=new FileAttachment(new FileInfo(@"..\..\TestFiles\grover.jpg"));
fileattachment.ContentType="image/jpeg";
emailmessage.AddMixedAttachment(fileattachment);
emailmessage.Send(TestAddressHelper.GetSmtpServer());
}
}
}
@@ -0,0 +1,248 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.IO;
using DotNetOpenMail;
using DotNetOpenMail.Utils;
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests
{
[TestFixture]
public class FileAttachmentTests
{
private static readonly ILog log = LogManager.GetLogger(typeof(FileAttachmentTests));
public FileAttachmentTests()
{
}
[SetUp]
public void SetUp()
{
}
[TearDown]
public void TearDown()
{
}
[Test]
public void TestFileFromStream()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="Here's your license";
emailmessage.TextPart=new TextAttachment("This is a license.\r\n\r\n"+
"We will spend your money on a new plasma TV.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>"+
"<p>This is a license.</p>\r\n"+
"<p>We will spend your money on a new <i>plasma TV</i>.</p>\r\n"+
"</body></html>");
MemoryStream stream=new MemoryStream();
StreamWriter sw=new StreamWriter(stream);
sw.WriteLine("this is some test data 1");
sw.WriteLine("this is some test data 2");
sw.WriteLine("this is some test data 3");
sw.WriteLine("this is some test data 4");
sw.Flush();
stream.Seek(0, SeekOrigin.Begin);
//BinaryReader br=new BinaryReader(stream);
FileAttachment fileAttachment=new FileAttachment(new StreamReader(stream));
//fileAttachment.ContentType
fileAttachment.FileName="License.txt";
fileAttachment.CharSet=System.Text.Encoding.ASCII;
fileAttachment.ContentType="text/plain";
emailmessage.AddMixedAttachment(fileAttachment);
//emailmessage.Send(TestAddressHelper.GetSmtpServer());
}
[Test]
public void TestBinaryFileFromStream()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="Here's your file";
emailmessage.TextPart=new TextAttachment("This a jpeg.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>"+
"<p>This a jpeg.</p>\r\n");
FileInfo fileinfo=new FileInfo(@"..\..\TestFiles\grover.jpg");
//FileInfo fileinfo=new FileInfo(@"..\..\TestFiles\casingTheJoint.jpg");
FileStream filestream = fileinfo.OpenRead();
MemoryStream stream=new MemoryStream();
StreamWriter sw=new StreamWriter(stream);
sw.Flush();
//BinaryReader br=new BinaryReader(stream);
BinaryReader br=new BinaryReader(filestream);
byte[] bytes=br.ReadBytes((int) fileinfo.Length);
br.Close();
FileAttachment fileAttachment=new FileAttachment(bytes);
//fileAttachment.ContentType
fileAttachment.FileName="grover.jpg";
fileAttachment.ContentType="image/jpeg";
emailmessage.AddMixedAttachment(fileAttachment);
emailmessage.Send(TestAddressHelper.GetSmtpServer());
}
[Test]
public void TestFileFromString()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="Here's your license";
emailmessage.TextPart=new TextAttachment("This is a license.\r\n\r\n"+
"We will spend your money on a new plasma TV.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>"+
"<p>This is a license.</p>\r\n"+
"<p>We will spend your money on a new <i>plasma TV</i>.</p>\r\n"+
"</body></html>");
String content="This is String Line 1\r\nThis is String Line 2";
FileAttachment fileAttachment=new FileAttachment(content);
//fileAttachment.ContentType
fileAttachment.FileName="License.txt";
fileAttachment.CharSet=System.Text.Encoding.ASCII;
fileAttachment.ContentType="text/plain";
fileAttachment.Encoding=DotNetOpenMail.Encoding.EncodingType.SevenBit;
emailmessage.AddMixedAttachment(fileAttachment);
//emailmessage.Send(TestAddressHelper.GetSmtpServer());
}
[Test]
public void TestLargerBinaryFileFromStream()
{
String filename="casingTheJoint.jpg";
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="Here's your file";
emailmessage.TextPart=new TextAttachment("This a zip file.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>"+
"<p>This a zip file.</p>\r\n");
FileInfo fileinfo=new FileInfo(@"..\..\TestFiles\"+filename);
FileStream filestream = fileinfo.OpenRead();
MemoryStream stream=new MemoryStream();
StreamWriter sw=new StreamWriter(stream);
sw.Flush();
//BinaryReader br=new BinaryReader(stream);
BinaryReader br=new BinaryReader(filestream);
byte[] bytes=br.ReadBytes((int) fileinfo.Length);
br.Close();
FileAttachment fileAttachment=new FileAttachment(bytes);
//fileAttachment.ContentType
fileAttachment.FileName=filename;
fileAttachment.ContentType="application/zip";
emailmessage.AddMixedAttachment(fileAttachment);
emailmessage.Send(TestAddressHelper.GetSmtpServer());
}
[Test]
public void TestDocFile()
{
EmailMessage mail = new EmailMessage();
FileInfo fileinfo=new FileInfo(@"..\..\TestFiles\TestWord.doc");
Assert.IsTrue(fileinfo.Exists);
FileAttachment fileAttachment = new FileAttachment(fileinfo);
fileAttachment.ContentType = "application/msword";
//EmailAddress emailAddress = new EmailAddress(emailAddressParam);
mail.TextPart=new TextAttachment("Here is your file");
mail.AddMixedAttachment(fileAttachment);
mail.FromAddress=TestAddressHelper.GetFromAddress();
mail.AddToAddress("outlook@mymailout.com");
SmtpServer smtpServer = TestAddressHelper.GetSmtpServer();
mail.Send(smtpServer);
}
}
}
@@ -0,0 +1,186 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.IO;
using DotNetOpenMail;
using DotNetOpenMail.Utils;
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests
{
[TestFixture]
public class FileAttachmentTests2
{
private static readonly ILog log = LogManager.GetLogger(typeof(FileAttachmentTests2));
public FileAttachmentTests2()
{
}
[SetUp]
public void SetUp()
{
}
[TearDown]
public void TearDown()
{
}
#region TestVariousAttachments
[Test]
public void TestVariousAttachments()
{
// Read from the file
FileAttachment fromfile=GetAttachmentFromFile(new FileInfo(@"..\..\TestFiles\acrobattestpage.pdf"));
Assert.IsNotNull(fromfile);
// Create from a stream reader (this won't work with binary attachments)
FileAttachment fromstreamreader=GetAttachmentFromStreamReader(new FileInfo(@"..\..\TestFiles\acrobattestpage.pdf"));
Assert.IsNotNull(fromstreamreader);
// Create from byte array
FileAttachment frombytearray=GetAttachmentFromByteArray(new FileInfo(@"..\..\TestFiles\acrobattestpage.pdf"));
Assert.IsNotNull(frombytearray);
// Create from a stream reader (this won't work with binary attachments)
FileAttachment frombinaryreader=GetAttachmentFromBinaryReader(new FileInfo(@"..\..\TestFiles\acrobattestpage.pdf"));
Assert.IsNotNull(frombinaryreader);
String fromFileStr=fromfile.ToDataString();
String fromByteArrayStr=frombytearray.ToDataString();
String fromStreamReaderStr=fromstreamreader.ToDataString();
String fromBinaryReaderStr=frombinaryreader.ToDataString();
log.Debug("FROM FILE: "+fromFileStr.Length+" bytes");
log.Debug("FROM BYTE ARRAY: "+fromByteArrayStr.Length+" bytes");
log.Debug("FROM STREAM READER: "+fromStreamReaderStr.Length+" bytes");
log.Debug("FROM BINARY READER: "+fromBinaryReaderStr.Length+" bytes");
Assert.AreEqual(fromFileStr, fromBinaryReaderStr);
}
#endregion
#region GetBasicMessage
private EmailMessage GetBasicMessage()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="PDF Test";
emailmessage.TextPart=new TextAttachment("This a PDF File");
emailmessage.HtmlPart=new HtmlAttachment("<p>This is a PDF File</p>\r\n");
return emailmessage;
}
#endregion
#region GetAttachmentFromByteArray
private FileAttachment GetAttachmentFromByteArray(FileInfo fileinfo)
{
FileStream filestream = fileinfo.OpenRead();
BinaryReader br=new BinaryReader(filestream);
byte[] bytes=br.ReadBytes((int) fileinfo.Length);
br.Close();
FileAttachment fileAttachment=new FileAttachment(bytes);
fileAttachment.Encoding=DotNetOpenMail.Encoding.EncodingType.Base64;
fileAttachment.FileName="acrobattestpage.pdf";
fileAttachment.ContentType="application/pdf";
return fileAttachment;
}
#endregion
#region GetAttachmentFromFile
private FileAttachment GetAttachmentFromFile(FileInfo fileinfo)
{
FileStream filestream = fileinfo.OpenRead();
FileAttachment fileAttachment=new FileAttachment(fileinfo);
fileAttachment.Encoding=DotNetOpenMail.Encoding.EncodingType.Base64;
fileAttachment.FileName="acrobattestpage.pdf";
fileAttachment.ContentType="application/pdf";
return fileAttachment;
}
#endregion
#region GetAttachmentFromStreamReader
private FileAttachment GetAttachmentFromStreamReader(FileInfo fileinfo)
{
FileStream filestream = fileinfo.OpenRead();
StreamReader streamreader=new StreamReader(filestream);
FileAttachment fileAttachment=new FileAttachment(streamreader);
//fileAttachment.ContentType
fileAttachment.Encoding=DotNetOpenMail.Encoding.EncodingType.Base64;
fileAttachment.FileName="acrobattestpage.pdf";
fileAttachment.ContentType="application/pdf";
return fileAttachment;
}
#endregion
#region GetAttachmentFromBinaryReader
private FileAttachment GetAttachmentFromBinaryReader(FileInfo fileinfo)
{
FileStream filestream = fileinfo.OpenRead();
BinaryReader binaryreader=new BinaryReader(filestream);
FileAttachment fileAttachment=new FileAttachment(binaryreader);
//fileAttachment.ContentType
fileAttachment.Encoding=DotNetOpenMail.Encoding.EncodingType.Base64;
fileAttachment.FileName="acrobattestpage.pdf";
fileAttachment.ContentType="application/pdf";
return fileAttachment;
}
#endregion
}
}
@@ -0,0 +1,26 @@
using System;
using DotNetOpenMail.Logging;
using log4net;
namespace DotNetOpenMailTests
{
/// <summary>
/// Summary description for Log4netLogger.
/// </summary>
public class Log4netLogger
{
private static readonly ILog log = LogManager.GetLogger(typeof(Log4netLogger));
public Log4netLogger()
{
}
public void Log(LogMessage message)
{
log.Debug(message.Sender.GetType().Name+" ["+DateTime.Now.ToShortTimeString()+"]: "+message.Message);
}
}
}
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.IO;
using DotNetOpenMail;
using DotNetOpenMail.Utils;
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests
{
[TestFixture]
public class QuickTest
{
SmtpServer _smtpserver=null;
private static readonly ILog log = LogManager.GetLogger(typeof(QuickTest));
public QuickTest()
{
}
[SetUp]
public void SetUp()
{
_smtpserver=TestAddressHelper.GetSmtpServer();
}
[TearDown]
public void TearDown()
{
}
[Test]
public void TestSend()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
//emailmessage.FromAddress=new EmailAddress("mike@bridgecanada.com", "Bridge, Mike");
//emailmessage.FromAddress=new EmailAddress("mike@bridgecanada.com", "<Mike Bridge>");
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="EmailMessageTests Test HTML and Text";
emailmessage.TextPart=new TextAttachment("This\r\nis the\r\ntext\r\npart.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br>\r\nis the<br>\r\n<strong>HTML</strong><br>\r\npart.</body></html>");
emailmessage.BodyText="This is a test";
emailmessage.AddCustomHeader("X-MyHeader1", "my header number one");
//emailmessage.AddCustomHeader("Sender", TestAddressHelper.GetToAddress().ToString());
Log4netLogger logger=new Log4netLogger();
_smtpserver.LogSmtpWrite+=(new SmtpServer.LogHandler(logger.Log));
_smtpserver.LogSmtpReceive+=(new SmtpServer.LogHandler(logger.Log));
_smtpserver.LogSmtpCompleted+=(new SmtpServer.LogHandler(logger.Log));
emailmessage.Send(_smtpserver);
}
}
}
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Globalization;
using DotNetOpenMail;
using log4net;
using NUnit.Framework;
namespace DotNetOpenMailTests
{
[TestFixture]
public class RFC2822DateTests
{
private static readonly ILog log = LogManager.GetLogger(typeof(RFC2822DateTests));
public RFC2822DateTests()
{
}
[SetUp]
public void SetUp()
{
}
[TearDown]
public void TearDown()
{
}
[Test]
public void TestSMTPDate()
{
TimeZone timezone=TimeZone.CurrentTimeZone;
DateTime datetime=new DateTime(2005, 2, 8, 9, 34,56);
String tzhours=String.Format("{0:00}", timezone.GetUtcOffset(datetime).Hours);
String tzminutes=String.Format("{0:00}", timezone.GetUtcOffset(datetime).Minutes);
String tzstring=tzhours+tzminutes;
if (timezone.GetUtcOffset(datetime).Hours >= 0)
{
tzstring="+"+tzstring;
}
RFC2822Date rfcdate=new RFC2822Date(datetime, timezone);
Assert.AreEqual("Tue, 8 Feb 2005 09:34:56 "+tzstring, rfcdate.ToString());
datetime=new DateTime(2005, 2, 8, 19, 34,56);
rfcdate=new RFC2822Date(datetime, timezone);
Assert.AreEqual("Tue, 8 Feb 2005 19:34:56 "+tzstring, rfcdate.ToString());
}
[Test]
public void TestNonEnglishSMTPDate()
{
CultureInfo japanese=new CultureInfo("ja-JP");
System.Threading.Thread.CurrentThread.CurrentCulture=japanese;
TimeZone timezone=TimeZone.CurrentTimeZone;
DateTime datetime=new DateTime(2005, 2, 8, 9, 34,56);
String tzhours=String.Format("{0:00}", timezone.GetUtcOffset(datetime).Hours);
String tzminutes=String.Format("{0:00}", timezone.GetUtcOffset(datetime).Minutes);
String tzstring=tzhours+tzminutes;
if (timezone.GetUtcOffset(datetime).Hours >= 0)
{
tzstring="+"+tzstring;
}
RFC2822Date rfcdate=new RFC2822Date(datetime, timezone);
Assert.AreEqual("Tue, 8 Feb 2005 09:34:56 "+tzstring, rfcdate.ToString());
datetime=new DateTime(2005, 2, 8, 19, 34,56);
rfcdate=new RFC2822Date(datetime, timezone);
Assert.AreEqual("Tue, 8 Feb 2005 19:34:56 "+tzstring, rfcdate.ToString());
}
}
}
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.IO;
using DotNetOpenMail;
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests
{
/// <summary>
/// Summary description for RawEmailMessageTests.
/// </summary>
[TestFixture]
public class RawEmailMessageTests
{
SmtpServer _smtpserver=null;
private static readonly ILog log = LogManager.GetLogger(typeof(RawEmailMessageTests));
[SetUp]
public void SetUp()
{
_smtpserver=TestAddressHelper.GetSmtpServer();
}
[TearDown]
public void TearDown() {}
public RawEmailMessageTests()
{
}
[Test]
public void TestRawEmail()
{
FileInfo contentfile=new FileInfo(@"..\..\TestFiles\ImportedEmail.txt");
Assert.IsTrue(contentfile.Exists);
StreamReader sr=new StreamReader(contentfile.OpenRead());
RawEmailMessage message=new RawEmailMessage();
message.Content=sr.ReadToEnd();
message.AddRcptToAddress(TestAddressHelper.GetToAddress());
message.MailFrom=TestAddressHelper.GetFromAddress();
message.Send(_smtpserver);
}
}
}
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using DotNetOpenMailTests.Resources; // change to tested dir
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests.Resources {
[TestFixture]
public class ARMTests {
private static readonly ILog log = LogManager.GetLogger(typeof(ARMTests));
public ARMTests() {
}
[SetUp]
public void SetUp() {}
[TearDown]
public void TearDown() {}
[Test]
public void Test() {
}
}
}
@@ -0,0 +1,72 @@
using System;
using System.IO;
using System.Text;
using System.Globalization;
using DotNetOpenMail;
using DotNetOpenMail.Utils;
using DotNetOpenMail.Encoding;
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests
{
[TestFixture]
public class RussianTests {
private static readonly ILog log = LogManager.GetLogger(typeof(RussianTests));
public RussianTests() {
}
[SetUp]
public void SetUp() {}
[TearDown]
public void TearDown() {}
[Test]
public void TestWindows1251() {
EmailMessage emailmessage = new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject = "ошибочка?";
emailmessage.HeaderCharSet = System.Text.Encoding.GetEncoding("windows-1251");
TextAttachment ta = new TextAttachment("\r\nнесколько строк по русски");
ta.CharSet = System.Text.Encoding.GetEncoding("windows-1251");
emailmessage.TextPart = ta;
emailmessage.Send(TestAddressHelper.GetSmtpServer());
Assert.IsTrue(emailmessage.ToDataString().IndexOf("Subject: =?windows-1251") > 0, "Missing windows-1251 in subject");
Assert.IsTrue(emailmessage.ToDataString().IndexOf("koi8-r") < 0);
}
[Test]
public void TestKOI8R()
{
EmailMessage emailmessage = new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject = "ошибочка?";
emailmessage.HeaderCharSet = System.Text.Encoding.GetEncoding("koi8-r");
TextAttachment ta = new TextAttachment("\r\nнесколько строк по русски");
ta.CharSet = System.Text.Encoding.GetEncoding("koi8-r");
emailmessage.TextPart = ta;
//log.Debug("1251");
//log.Debug(emailmessage.ToDataString());
emailmessage.Send(TestAddressHelper.GetSmtpServer());
Assert.IsTrue(emailmessage.ToDataString().IndexOf("Subject: =?koi8-r") > 0, "Missing koi8-r in subject");
Assert.IsTrue(emailmessage.ToDataString().IndexOf("windows-1251") < 0);
}
}
}
@@ -0,0 +1,309 @@
using System;
using System.Net;
using DotNetOpenMail;
using DotNetOpenMail.SmtpAuth;
using DotNetOpenMail.Encoding;
using NUnit.Framework;
using log4net;
using NMock;
namespace DotNetOpenMailTests.SmtpAuth {
[TestFixture]
public class LocalAuthTests {
private static readonly ILog log = LogManager.GetLogger(typeof(LocalAuthTests));
public LocalAuthTests() {
}
[SetUp]
public void SetUp() {}
[TearDown]
public void TearDown() {}
#region GetTestHtmlAndTextMessage
private EmailMessage GetTestHtmlAndTextMessage()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="EmailMessageTests Test HTML and Text";
emailmessage.TextPart=new TextAttachment("This\r\nis the\r\ntext\r\npart.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br>\r\nis the<br>\r\n<strong>HTML</strong><br>\r\npart.</body></html>");
emailmessage.AddCustomHeader("X-MyHeader1", "my header number one");
emailmessage.AddCustomHeader("X-MyHeader2", "my header number two");
return emailmessage;
}
#endregion
/*
* Test for this exchange:
* S: 220 esmtp.example.com ESMTP
* C: ehlo client.example.com
* S: 250-esmtp.example.com
* S: 250-PIPELINING
* S: 250-8BITMIME
* S: 250-SIZE 255555555
* S: 250 AUTH LOGIN PLAIN CRAM-MD5
* C: auth login
* S: 334 VXNlcm5hbWU6
* C: avlsdkfj
* S: 334 UGFzc3dvcmQ6
* C: lkajsdfvlj
* S: 535 authentication failed (#5.7.1)
*/
#region TestSimpleSmtpNegotiationWithAuth
[Test]
public void TestSimpleSmtpNegotiationWithAuth()
{
SmtpServer smtpserver=new SmtpServer("localhost");
smtpserver.SmtpAuthToken=new SmtpAuthToken("test", "test");
Base64Encoder encoder=Base64Encoder.GetInstance();
String base64Username=encoder.EncodeString(smtpserver.SmtpAuthToken.UserName, System.Text.Encoding.ASCII );
String base64Password=encoder.EncodeString(smtpserver.SmtpAuthToken.Password, System.Text.Encoding.ASCII );
EmailMessage emailMessage=GetTestHtmlAndTextMessage();
IMock mockSmtpProxy = new DynamicMock(typeof(ISmtpProxy));
mockSmtpProxy.ExpectAndReturn("Open", new SmtpResponse(220, "welcome to the mock object server"), null);
EhloSmtpResponse ehloResponse=new EhloSmtpResponse();
ehloResponse.AddAvailableAuthType("login");
ehloResponse.Message="OK";
ehloResponse.ResponseCode=250;
mockSmtpProxy.ExpectAndReturn("Ehlo",ehloResponse , Dns.GetHostName());
mockSmtpProxy.ExpectAndReturn("Auth", new SmtpResponse(334, encoder.EncodeString("Username:", System.Text.Encoding.ASCII)), "login");
mockSmtpProxy.ExpectAndReturn("SendString", new SmtpResponse(334, encoder.EncodeString("Password:",System.Text.Encoding.ASCII)), base64Username);
mockSmtpProxy.ExpectAndReturn("SendString", new SmtpResponse(235, "Hooray, Authenticated"), base64Password);
mockSmtpProxy.ExpectAndReturn("MailFrom", new SmtpResponse(250, "mail from"), emailMessage.FromAddress);
foreach (EmailAddress rcpttoaddr in emailMessage.ToAddresses)
{
mockSmtpProxy.ExpectAndReturn("RcptTo", new SmtpResponse(250, "receipt to"), rcpttoaddr);
}
mockSmtpProxy.ExpectAndReturn("Data", new SmtpResponse(354, "data open"), null);
mockSmtpProxy.ExpectAndReturn("WriteData", new SmtpResponse(250, "data"), emailMessage.ToDataString());
mockSmtpProxy.ExpectAndReturn("Quit", new SmtpResponse(221, "quit"), null);
mockSmtpProxy.Expect("Close", null);
ISmtpProxy smtpProxy= (ISmtpProxy) mockSmtpProxy.MockInstance;
smtpserver.OverrideSmtpProxy(smtpProxy);
try
{
emailMessage.Send(smtpserver);
}
catch (SmtpException ex)
{
log.Debug("Exception was "+ex.Message);
log.Debug(ex.StackTrace);
throw ex;
}
}
#endregion
#region TestForcedLoginSmtpNegotiationWithAuth
[Test]
public void TestForcedLoginSmtpNegotiationWithAuth()
{
SmtpServer smtpserver=new SmtpServer("localhost");
smtpserver.SmtpAuthToken=new LoginAuthToken("test", "testtest");
Base64Encoder encoder=Base64Encoder.GetInstance();
String base64Username=encoder.EncodeString(smtpserver.SmtpAuthToken.UserName, System.Text.Encoding.ASCII );
String base64Password=encoder.EncodeString(smtpserver.SmtpAuthToken.Password, System.Text.Encoding.ASCII );
EmailMessage emailMessage=GetTestHtmlAndTextMessage();
IMock mockSmtpProxy = new DynamicMock(typeof(ISmtpProxy));
mockSmtpProxy.ExpectAndReturn("Open", new SmtpResponse(220, "welcome to the mock object server"), null);
EhloSmtpResponse ehloResponse=new EhloSmtpResponse();
ehloResponse.AddAvailableAuthType("login");
ehloResponse.Message="OK";
ehloResponse.ResponseCode=250;
mockSmtpProxy.ExpectAndReturn("Ehlo",ehloResponse , Dns.GetHostName());
mockSmtpProxy.ExpectAndReturn("Auth", new SmtpResponse(334, encoder.EncodeString("Username:", System.Text.Encoding.ASCII)), "login");
mockSmtpProxy.ExpectAndReturn("SendString", new SmtpResponse(334, encoder.EncodeString("Password:",System.Text.Encoding.ASCII)), base64Username);
mockSmtpProxy.ExpectAndReturn("SendString", new SmtpResponse(235, "Hooray, Authenticated"), base64Password);
mockSmtpProxy.ExpectAndReturn("MailFrom", new SmtpResponse(250, "mail from"), emailMessage.FromAddress);
foreach (EmailAddress rcpttoaddr in emailMessage.ToAddresses)
{
mockSmtpProxy.ExpectAndReturn("RcptTo", new SmtpResponse(250, "receipt to"), rcpttoaddr);
}
mockSmtpProxy.ExpectAndReturn("Data", new SmtpResponse(354, "data open"), null);
mockSmtpProxy.ExpectAndReturn("WriteData", new SmtpResponse(250, "data"), emailMessage.ToDataString());
mockSmtpProxy.ExpectAndReturn("Quit", new SmtpResponse(221, "quit"), null);
mockSmtpProxy.Expect("Close", null);
ISmtpProxy smtpProxy= (ISmtpProxy) mockSmtpProxy.MockInstance;
smtpserver.OverrideSmtpProxy(smtpProxy);
try
{
emailMessage.Send(smtpserver);
}
catch (SmtpException ex)
{
log.Debug("Exception was "+ex.Message);
log.Debug(ex.StackTrace);
throw ex;
}
}
#endregion
#region TestFailedSmtpNegotiationWithAuth
[Test]
public void TestFailedSmtpNegotiationWithAuth()
{
SmtpServer smtpserver=new SmtpServer("localhost");
smtpserver.SmtpAuthToken=new SmtpAuthToken("test", "test");
Base64Encoder encoder=Base64Encoder.GetInstance();
String base64Username=encoder.EncodeString(smtpserver.SmtpAuthToken.UserName, System.Text.Encoding.ASCII );
String base64Password=encoder.EncodeString(smtpserver.SmtpAuthToken.Password, System.Text.Encoding.ASCII );
EmailMessage emailMessage=GetTestHtmlAndTextMessage();
IMock mockSmtpProxy = new DynamicMock(typeof(ISmtpProxy));
mockSmtpProxy.ExpectAndReturn("Open", new SmtpResponse(220, "welcome to the mock object server"), null);
EhloSmtpResponse ehloResponse=new EhloSmtpResponse();
ehloResponse.AddAvailableAuthType("login");
ehloResponse.Message="OK";
ehloResponse.ResponseCode=250;
mockSmtpProxy.ExpectAndReturn("Ehlo", ehloResponse , Dns.GetHostName());
mockSmtpProxy.ExpectAndReturn("Auth", new SmtpResponse(554, "Unrecognized auth type"), "login");
ISmtpProxy smtpProxy= (ISmtpProxy) mockSmtpProxy.MockInstance;
smtpserver.OverrideSmtpProxy(smtpProxy);
/*
mockSmtpProxy.ExpectAndReturn("SendString", new SmtpResponse(554, "Invalid UserName"), base64Username);
mockSmtpProxy.ExpectAndReturn("SendString", new SmtpResponse(554, "Invalid Password"), base64Password);
mockSmtpProxy.ExpectAndReturn("MailFrom", new SmtpResponse(250, "mail from"), emailMessage.FromAddress);
foreach (EmailAddress rcpttoaddr in emailMessage.ToAddresses)
{
mockSmtpProxy.ExpectAndReturn("RcptTo", new SmtpResponse(250, "receipt to"), rcpttoaddr);
}
mockSmtpProxy.ExpectAndReturn("Data", new SmtpResponse(354, "data open"), null);
mockSmtpProxy.ExpectAndReturn("WriteData", new SmtpResponse(250, "data"), emailMessage.ToDataString());
mockSmtpProxy.ExpectAndReturn("Quit", new SmtpResponse(221, "quit"), null);
mockSmtpProxy.Expect("Close", null);
*/
try
{
emailMessage.Send(smtpserver);
Assert.Fail("The auth type is wrong");
}
catch (SmtpException ex)
{
log.Debug("ERROR CODE IS "+554);
Assert.AreEqual(554,ex.ErrorCode);
}
}
#endregion
#region TestSmtpNegotiationWithAuthTimeout
[Test]
[Ignore("Not completed yet")]
public void TestSmtpNegotiationWithAuthTimeout()
{
SmtpServer smtpserver=new SmtpServer("localhost");
smtpserver.SmtpAuthToken=new LoginAuthToken("test", "test");
Base64Encoder encoder=Base64Encoder.GetInstance();
String base64Username=encoder.EncodeString(smtpserver.SmtpAuthToken.UserName, System.Text.Encoding.ASCII );
String base64Password=encoder.EncodeString(smtpserver.SmtpAuthToken.Password, System.Text.Encoding.ASCII );
EmailMessage emailMessage=GetTestHtmlAndTextMessage();
/*
IMock mockSmtpProxy = new DynamicMock(typeof(ISmtpProxy));
mockSmtpProxy.ExpectAndReturn("Open", new SmtpResponse(220, "welcome to the mock object server"), null);
EhloSmtpResponse ehloResponse=new EhloSmtpResponse();
ehloResponse.AddAvailableAuthType("login");
ehloResponse.Message="OK";
ehloResponse.ResponseCode=250;
mockSmtpProxy.ExpectAndReturn("Ehlo",ehloResponse , Dns.GetHostName());
mockSmtpProxy.ExpectAndReturn("Auth", new SmtpResponse(334, encoder.EncodeString("Username:", System.Text.Encoding.ASCII)), "login");
mockSmtpProxy.ExpectAndReturn("SendString", new SmtpResponse(334, encoder.EncodeString("Password:",System.Text.Encoding.ASCII)), base64Username);
mockSmtpProxy.ExpectAndReturn("SendString", new SmtpResponse(235, "Hooray, Authenticated"), base64Password);
mockSmtpProxy.ExpectAndReturn("MailFrom", new SmtpResponse(250, "mail from"), emailMessage.FromAddress);
foreach (EmailAddress rcpttoaddr in emailMessage.ToAddresses)
{
mockSmtpProxy.ExpectAndReturn("RcptTo", new SmtpResponse(250, "receipt to"), rcpttoaddr);
}
mockSmtpProxy.ExpectAndReturn("Data", new SmtpResponse(354, "data open"), null);
mockSmtpProxy.ExpectAndReturn("WriteData", new SmtpResponse(250, "data"), emailMessage.ToDataString());
mockSmtpProxy.ExpectAndReturn("Quit", new SmtpResponse(221, "quit"), null);
mockSmtpProxy.Expect("Close", null);
ISmtpProxy smtpProxy= (ISmtpProxy) mockSmtpProxy.MockInstance;
*/
smtpserver.OverrideSmtpProxy(new MockedSlowProxy());
try
{
emailMessage.Send(smtpserver);
Assert.Fail("This should have thrown an SmtpException indicating a timeout.");
}
catch (SmtpException ex)
{
log.Debug("Exception was "+ex.Message);
log.Debug(ex.StackTrace);
//throw ex;
}
}
#endregion
}
}
@@ -0,0 +1,33 @@
using System;
using System.Net.Sockets;
using DotNetOpenMail;
using DotNetOpenMail.SmtpAuth;
namespace DotNetOpenMailTests.SmtpAuth
{
/// <summary>
/// Summary description for MockedSlowServer.
/// </summary>
public class MockedSlowProxy : MockedSmtpProxy
{
public MockedSlowProxy()
{
}
public override SmtpResponse Open()
{
return new SmtpResponse(220, "Welcome to the Slow Server");
}
public override SmtpResponse Auth(String localHostName)
{
//int timeout=10000;
//System.Threading.Thread.Sleep(timeout);
throw new SocketException(10060);
//throw new ApplicationException("Waited "+timeout+" millisseconds");
}
}
}
@@ -0,0 +1,94 @@
using System;
using DotNetOpenMail;
using DotNetOpenMail.SmtpAuth;
using DotNetOpenMail.Encoding;
namespace DotNetOpenMailTests.SmtpAuth
{
/// <summary>
/// Summary description for MockedSmtpProxy.
/// </summary>
public abstract class MockedSmtpProxy : ISmtpProxy
{
public MockedSmtpProxy()
{
//
// TODO: Add constructor logic here
//
}
public virtual SmtpResponse Open()
{
throw new ApplicationException("Open Not implemented yet");
}
public SmtpResponse Helo(String localHostName)
{
throw new ApplicationException("Helo Not implemented yet");
}
public virtual SmtpResponse Auth(String localHostName)
{
Base64Encoder encoder=Base64Encoder.GetInstance();
return new SmtpResponse(334, encoder.EncodeString("Username:", System.Text.Encoding.ASCII));
}
public virtual EhloSmtpResponse Ehlo(String localHostName)
{
EhloSmtpResponse ehloResponse=new EhloSmtpResponse();
ehloResponse.AddAvailableAuthType("login");
ehloResponse.Message="OK";
ehloResponse.ResponseCode=250;
return ehloResponse;
}
public SmtpResponse MailFrom(EmailAddress rcptto)
{
throw new ApplicationException("MailFrom Not implemented yet");
}
public SmtpResponse RcptTo(EmailAddress rcptto)
{
throw new ApplicationException("RcptTo Not implemented yet");
}
public SmtpResponse Data()
{
throw new ApplicationException("Data Not implemented yet");
}
public SmtpResponse WriteData(String str)
{
throw new ApplicationException("WriteData Not implemented yet");
}
public SmtpResponse Quit()
{
throw new ApplicationException("Quit Not implemented yet");
}
public void Close()
{
// do nothing
}
public SmtpResponse SendString(String str)
{
throw new ApplicationException("SendString Not implemented yet");
}
public bool CaptureSmtpConversation {
get
{
return false;
}
set
{
// IGNORE
}
}
}
}
@@ -0,0 +1,94 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using DotNetOpenMail;
using NUnit.Framework;
using log4net;
namespace DotNetOpenMailTests {
[TestFixture]
public class SmtpProxyTests {
SmtpServer _smtpserver=null;
private static readonly ILog log = LogManager.GetLogger(typeof(SmtpProxyTests));
public SmtpProxyTests() {
}
[SetUp]
public void SetUp()
{
_smtpserver=TestAddressHelper.GetSmtpServer();
}
[TearDown]
public void TearDown() {}
[Test]
public void TestBasicSend()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="EmailMessageTests TestBasicSend";
emailmessage.TextPart=new TextAttachment("This\r\nis the\r\ntext\r\npart.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br>\r\nis the<br>\r\n<strong>HTML</strong><br>\r\npart.</body></html>");
emailmessage.EnvelopeFromAddress=new EmailAddress("test@bridgecanada.com");
emailmessage.Send(_smtpserver);
// this doesn't test anything yet
}
[Test]
public void TestEmailWithDot()
{
//SmtpServer smtpserver=TestAddressHelper.GetSmtpServer();
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="EmailMessageTests Test Dot";
emailmessage.TextPart=new TextAttachment("This\r\n.is the\r\n..text\r\n...part.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br>\r\n..is the<br>\r\n..<strong>HTML</strong><br>\r\npart.</body></html>");
emailmessage.Send(_smtpserver);
// this doesn't test anything yet
//log.Debug("MESSAGE: "+emailmessage.ToDataString());
}
}
}
@@ -0,0 +1,76 @@
using System;
using System.Net;
using DotNetOpenMail;
using NUnit.Framework;
using log4net;
using NMock;
namespace DotNetOpenMailTests.SmtpServerTests {
[TestFixture]
public class SmtpServerTests {
private static readonly ILog log = LogManager.GetLogger(typeof(SmtpServerTests));
public SmtpServerTests() {
}
[SetUp]
public void SetUp() {}
[TearDown]
public void TearDown() {}
private EmailMessage GetTestHtmlAndTextMessage()
{
EmailMessage emailmessage=new EmailMessage();
emailmessage.FromAddress=TestAddressHelper.GetFromAddress();
emailmessage.AddToAddress(TestAddressHelper.GetToAddress());
emailmessage.Subject="EmailMessageTests Test HTML and Text";
emailmessage.TextPart=new TextAttachment("This\r\nis the\r\ntext\r\npart.");
emailmessage.HtmlPart=new HtmlAttachment("<html><body>This<br>\r\nis the<br>\r\n<strong>HTML</strong><br>\r\npart.</body></html>");
emailmessage.AddCustomHeader("X-MyHeader1", "my header number one");
emailmessage.AddCustomHeader("X-MyHeader2", "my header number two");
return emailmessage;
}
[Test]
public void TestSimpleSmtpNegotiation()
{
SmtpServer smtpserver=new SmtpServer("localhost");
EmailMessage emailMessage=GetTestHtmlAndTextMessage();
IMock mockSmtpProxy = new DynamicMock(typeof(ISmtpProxy));
mockSmtpProxy.ExpectAndReturn("Open", new SmtpResponse(220, "welcome to the mock object server"), null);
mockSmtpProxy.ExpectAndReturn("Helo", new SmtpResponse(250, "helo"), Dns.GetHostName());
mockSmtpProxy.ExpectAndReturn("MailFrom", new SmtpResponse(250, "mail from"), emailMessage.FromAddress);
foreach (EmailAddress rcpttoaddr in emailMessage.ToAddresses)
{
mockSmtpProxy.ExpectAndReturn("RcptTo", new SmtpResponse(250, "receipt to"), rcpttoaddr);
}
mockSmtpProxy.ExpectAndReturn("Data", new SmtpResponse(354, "data open"), null);
mockSmtpProxy.ExpectAndReturn("WriteData", new SmtpResponse(250, "data"), emailMessage.ToDataString());
mockSmtpProxy.ExpectAndReturn("Quit", new SmtpResponse(221, "quit"), null);
mockSmtpProxy.Expect("Close", null);
ISmtpProxy smtpProxy= (ISmtpProxy) mockSmtpProxy.MockInstance;
smtpserver.OverrideSmtpProxy(smtpProxy);
emailMessage.Send(smtpserver);
}
}
}
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using DotNetOpenMail;
namespace DotNetOpenMailTests
{
/// <summary>
/// Summary description for TestAddressHelper.
/// </summary>
public class TestAddressHelper
{
public TestAddressHelper()
{
}
public static EmailAddress GetFromAddress()
{
//return new EmailAddress("mike@bridgecanada.com", "Test Sender");
String email=System.Configuration.ConfigurationSettings.AppSettings["dnom.test.fromaddress"];
if (email==null)
{
throw new ApplicationException("Please add the key \"dnom.test.fromaddress\" to your .config file");
}
return new EmailAddress(email, "NUnit Test Sender");
}
public static EmailAddress GetToAddress()
{
String email=System.Configuration.ConfigurationSettings.AppSettings["dnom.test.toaddress"];
if (email==null)
{
throw new ApplicationException("Please add the key \"dnom.test.toaddress\" to your .config file");
}
return new EmailAddress(email, "NUnit Test Recipient");
}
public static SmtpServer GetSmtpServer()
{
String smtpserver=System.Configuration.ConfigurationSettings.AppSettings["dnom.test.smtp.server"];
if (smtpserver==null)
{
throw new ApplicationException("Please add the key \"dnom.test.smtp.server\" to your .config file");
}
return new SmtpServer(smtpserver);
}
}
}
@@ -0,0 +1,4 @@
Subject: This is a test
To: mike@bridgecanada.com
This is a test.
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

@@ -0,0 +1,69 @@
using System;
using DotNetOpenMail;
using DotNetOpenMail.Utils;
using log4net;
using NUnit.Framework;
namespace DotNetOpenMailTests.Utils
{
[TestFixture]
public class EmailAddressParserTests
{
private static readonly ILog log = LogManager.GetLogger(typeof(EmailAddressParserTests));
public EmailAddressParserTests()
{
}
[SetUp]
public void SetUp()
{
}
[TearDown]
public void TearDown()
{
}
[Test]
public void TestParser()
{
EmailAddressParser emailaddressparser=new EmailAddressParser();
String name1="Test Tester";
String email1="test@domain.com";
EmailAddress emailaddress=emailaddressparser.ParseRawEmailAddress(String.Format("{0} <{1}>", name1, email1));
Assert.IsNull(emailaddressparser.LastError);
Assert.IsNotNull(emailaddress, emailaddressparser.LastError);
Assert.AreEqual(name1, emailaddress.Name);
Assert.AreEqual(email1, emailaddress.Email);
emailaddress=emailaddressparser.ParseRawEmailAddress(email1);
Assert.IsNull(emailaddressparser.LastError);
Assert.IsNotNull(emailaddress, emailaddressparser.LastError);
Assert.AreEqual("", emailaddress.Name);
Assert.AreEqual(email1, emailaddress.Email);
emailaddress=emailaddressparser.ParseRawEmailAddress(String.Format("\"{0}\" <{1}>", name1, email1));
Assert.IsNotNull(emailaddress, emailaddressparser.LastError);
Assert.IsNull(emailaddressparser.LastError, emailaddressparser.LastError);
Assert.AreEqual("\""+name1+"\"", emailaddress.Name);
Assert.AreEqual(email1, emailaddress.Email);
emailaddress=emailaddressparser.ParseRawEmailAddress(String.Format("{0} <{1}>", name1, "test@localhost"));
Assert.IsNotNull(emailaddress, emailaddressparser.LastError);
Assert.IsNull(emailaddressparser.LastError, emailaddressparser.LastError);
Assert.AreEqual(name1, emailaddress.Name);
Assert.AreEqual("test@localhost", emailaddress.Email);
}
}
}
+85
View File
@@ -0,0 +1,85 @@
Version 0.5.8 beta: 24-May-2006
- Fixed buffering problem while doing base64-encoding
- Fixed missing ContentID in FileAttachment
- Added BinaryReader support for FileAttachment.
Version 0.5.7 beta: 17-Dec-2005
- Added event delegates to SmtpServer to listen to the SMTP conversation
- Deprecated the use of CaptureSmtpConversation
- Added simple version of email address string parser.
- Added a potential patch for piping a file attachment from memory
Version 0.5.6 beta: 16-Sep-2005
- Fixed SMTP AUTH LOCAL negotiation where the server returns multiple types
- SmtpProxy loops through multiline EHLO response correctly.
Version 0.5.5 beta: 25-Aug-2005
- Fixed handling of RFC-2822 "special" characters in email name.
- Added nicer error message when "From" name is missing.
Version 0.5.4 beta: 19-Aug-2005
- Replaced incorrect call to BodyName in QPEncoder and Base64Encoder with call
to HeaderName
- Added workaround for incorrect value returned by the .net framework for
Russian Windows-1251 (Encoding.GetEncoding("windows-1251").BodyName)
- Added error checking for truncated server responses of less than 3
characters.
- Fixed various incorrect numerical references to RFCs.
- Fixed QP-encoding of the question mark in message headers.
Version 0.5.3 beta: 3-Aug-2005
- Fixed RFC2822Date class to be independent of the deployment system default.
- Added ability to view the SMTP conversation in the SmtpServer class.
Version 0.5.2 beta: 30-May-2005
- Added check for empty charset for Header in both EmailAddress and
QPEncoder (default is iso-8859-1)
- Fixed the QPEncoder wrapping algorithm for long headers.
- An extra line was removed after a mimeheader which was pushing
custom headers into the mail body.
Version 0.5.1 beta: 26-Apr-2005
- Added ability to create FileAttachment from an in-memory byte array
- Fixed suppression of SMTP error on rejected RCPT TO address.
- Added NMock 1.1 to the source distribution.
- Added LOGIN protocol for SMTP AUTH.
- Refactored the SmtpProxy and SmtpServer to allow for Mocking
up various SMTP servers and SMTP protocol exchanges.
Version 0.5.0 beta: 1-Apr-2005
- Added NDoc documentation
- Added ability to create FileAttachment from a string
Version 0.4.0 beta: 1-Apr-2005
- Botched the Subversion tag
Version 0.3.1: 3-Mar-2005
- Added 7bit and 8bit options to encoder
- Fixed Camel Casing on web site, added example for next point
- Added ability to create FileAttachment from a reader
Version 0.3: 18-Feb-2005
- Added French localization
- Added modified examples from the web site as NUnit tests
to ensure they work
- Added ability to change Encoding and character set for
something other than latin-1. The API for specifying
the encoding changed.
- Fixed quoted printable to work with multibyte characters.
Version 0.2.1: 9-Feb-2005
- Initial Release
+40
View File
@@ -0,0 +1,40 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.106
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetOpenMail", "DotNetOpenMail\DotNetOpenMail.csproj", "{6FBB299F-81A1-49EA-B00A-E916F8F797B3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetOpenMailTests", "DotNetOpenMailTests\DotNetOpenMailTests.csproj", "{74F3DCD7-1325-4968-B466-38618A380CE9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{643C301A-B110-41E7-B0F7-FA2CA4AE335D}"
ProjectSection(SolutionItems) = preProject
CHANGES.txt = CHANGES.txt
DotNetOpenMailTests.dll.config = DotNetOpenMailTests.dll.config
DotNetOpenMailTests.dll.config.demo = DotNetOpenMailTests.dll.config.demo
DotNetOpenMailTests.dll.log4net = DotNetOpenMailTests.dll.log4net
LICENSE.txt = LICENSE.txt
README.txt = README.txt
README_NUNIT.txt = README_NUNIT.txt
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6FBB299F-81A1-49EA-B00A-E916F8F797B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FBB299F-81A1-49EA-B00A-E916F8F797B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FBB299F-81A1-49EA-B00A-E916F8F797B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FBB299F-81A1-49EA-B00A-E916F8F797B3}.Release|Any CPU.Build.0 = Release|Any CPU
{74F3DCD7-1325-4968-B466-38618A380CE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{74F3DCD7-1325-4968-B466-38618A380CE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{74F3DCD7-1325-4968-B466-38618A380CE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {31BC050A-2A12-4377-B072-BA9302262B6A}
EndGlobalSection
EndGlobal
@@ -0,0 +1,354 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.IO;
using System.Text;
using DotNetOpenMail.Encoding;
namespace DotNetOpenMail
{
/// <summary>
/// This is an abstract version of the email attachment. It may or
/// may not contain content, a character encoding method, a
/// mime-encoding method, a content-type designation, a content-id
/// designation, among other things
/// </summary>
public abstract class AbstractEmailAttachment : IEmailStringable
{
internal static readonly String CONTENTTYPE="Content-Type";
internal static readonly String CONTENTTRANSFERENCODING="Content-Transfer-Encoding";
internal static readonly String CONTENTDIPOSITION="Content-Disposition";
internal static readonly String CONTENTID="Content-ID";
internal static readonly String CONTENTDESCRIPTION="Content-Description";
internal static readonly String CHARSET="charset";
/// <summary>
/// The mail encoding type (e.g. quoted-printable, etc)
/// </summary>
protected EncodingType _encodingtype;
/// <summary>
/// The "content type" of the attachment
/// </summary>
protected String _contenttype;
/// <summary>
/// The content-transfer encoding of the attachment
/// </summary>
protected String _contenttransferencoding;
/// <summary>
/// The content disposition of the attachment
/// </summary>
protected String _contentdisposition;
/// <summary>
/// The content description of the attachment
/// </summary>
protected String _contentdescription;
/// <summary>
/// The character set of the encoded text
/// </summary>
protected System.Text.Encoding _charset=null;
/// <summary>
/// The unencoded contents, as a string (optional)
/// </summary>
protected String _contents=null;
/// <summary>
/// An optional content id
/// </summary>
protected String _contentid=null;
/// <summary>
/// The file name to identify the content.
/// (This can be different from the actual file name,
/// if there was one.)
/// </summary>
protected String _filename=null;
/// <summary>
/// The file source to read from
/// </summary>
protected FileInfo _fileinfo=null;
/// <summary>
/// The binary source of the file
/// </summary>
protected Byte[] _contentbytes=null;
/// <summary>
/// Empty constructor
/// </summary>
public AbstractEmailAttachment()
{
}
#region GetEncodedContents
/// <summary>
/// Get the contents, encoded for shipping via SMTP
/// </summary>
/// <param name="encoder">The encoder to encode the contents</param>
/// <returns>returns the encoded string, ready for SMTP transfer</returns>
internal virtual String GetEncodedContents(IEncoder encoder)
{
StringBuilder sb=new StringBuilder();
System.Text.Encoding charset=null;
if (_charset==null)
{
charset=System.Text.Encoding.UTF8;
}
else
{
charset=this._charset;
}
if (_contents!=null)
{
encoder.Encode(new StringReader(_contents), new StringWriter(sb), charset);
}
else if (_fileinfo!=null)
{
encoder.Encode(_fileinfo.OpenRead(), new StringWriter(sb), charset);
}
else if (_contentbytes!=null)
{
encoder.Encode(new BinaryReader(new MemoryStream(_contentbytes)), new StringWriter(sb));
}
String encodedcontents=sb.ToString();
if (encodedcontents.Length!=0 && encodedcontents[encodedcontents.Length-1]!='\n')
{
return encodedcontents+SmtpProxy.ENDOFLINE+SmtpProxy.ENDOFLINE;
}
else
{
return encodedcontents+SmtpProxy.ENDOFLINE;
}
}
#endregion
#region ToDataString
/// <summary>
/// Return the encoded contents, including mime
/// header.
/// </summary>
/// <returns></returns>
public String ToDataString()
{
IEncoder encoder=EncoderFactory.GetEncoder(Encoding);
StringBuilder sb=new StringBuilder();
sb.Append(GetInternalMimeHeader(encoder));
sb.Append(GetEncodedContents(encoder));
return sb.ToString();
}
#endregion
#region Encoding
/// <summary>
/// The encoding type for this attachment.
/// </summary>
public EncodingType Encoding
{
get {return _encodingtype;}
set {_encodingtype=value;}
}
#endregion
#region ContentType
/// <summary>
/// The "content type" of the attachment
/// </summary>
public String ContentType
{
get {return _contenttype;}
set {_contenttype=value;}
}
#endregion
#region CharSet
/// <summary>
/// The character set of the encoded text
/// </summary>
public System.Text.Encoding CharSet
{
get {return _charset;}
set {_charset=value;}
}
#endregion
#region ContentId
/// <summary>
/// An optional content id that is used to refer to
/// the attachment from elsewhere within a multipart/related
/// email.
/// </summary>
public String ContentId
{
get {return _contentid;}
set {_contentid=value;}
}
#endregion
#region FileName
/// <summary>
/// The file name to attach to the attachment.
/// </summary>
public String FileName
{
get {return _filename;}
set {_filename=value;}
}
#endregion
#region Contents
/// <summary>
/// The unencoded contents, as a string (optional)
/// </summary>
public String Contents
{
get {return _contents;}
set {_contents=value;}
}
#endregion
#region ContentBytes
/// <summary>
/// The raw bytes of the content (if this is the way
/// it was set.)
/// </summary>
public byte[] ContentBytes
{
get {return _contentbytes;}
set {_contentbytes=value;}
}
#endregion
#region GetInternalMimeHeader
/// <summary>
/// Create the internal mime header, as found on the
/// mime-attachment itself.
/// </summary>
/// <param name="encoder"></param>
/// <returns></returns>
protected String GetInternalMimeHeader(IEncoder encoder)
{
return MakeContentType()+
MakeTransferEncoding(encoder)+
MakeContentId()+
MakeContentDisposition()+
MakeContentDescription()+
SmtpProxy.ENDOFLINE;
}
#endregion
#region MakeContentType
private String MakeContentType()
{
StringBuilder sb=new StringBuilder(AbstractEmailAttachment.CONTENTTYPE+": "+ContentType+";"+SmtpProxy.ENDOFLINE);
if (_charset!=null)
{
// changed by Pietrovich to fix
// windows-1251 .NET encoding bug.
// windows-1251 BodyName returns "koi8-r"
// instead of "windows-1251"
// but still encodes string as windows-1251
string bodyName = _charset.BodyName;
//#if (FORCEWIN1251)
if ("koi8-r" == _charset.BodyName && "windows-1251" == _charset.HeaderName)
{
bodyName = _charset.HeaderName;
}
//#endif
sb.Append(" "+AbstractEmailAttachment.CHARSET + "=\"" +
bodyName + "\""+SmtpProxy.ENDOFLINE);
// _charset.BodyName + "\""+SmtpProxy.ENDOFLINE);
}
if (FileName!=null)
{
sb.Append(" name=\""+FileName+"\""+SmtpProxy.ENDOFLINE);
}
return sb.ToString();
}
#endregion
#region MakeTransferEncoding
private String MakeTransferEncoding(IEncoder encoder)
{
return AbstractEmailAttachment.CONTENTTRANSFERENCODING+": "+encoder.ContentTransferEncodingString+SmtpProxy.ENDOFLINE;
}
#endregion
#region MakeContentId
private String MakeContentId()
{
if (ContentId!=null)
{
return AbstractEmailAttachment.CONTENTID+": <" + ContentId + ">" + SmtpProxy.ENDOFLINE;
}
return "";
}
#endregion
#region MakeContentDisposition
private String MakeContentDisposition()
{
if (ContentId!=null)
{
return "";
}
if (ContentType!=null && FileName !=null)
{
return AbstractEmailAttachment.CONTENTDIPOSITION+": attachment;"+SmtpProxy.ENDOFLINE+
" filename=\""+FileName+"\""+SmtpProxy.ENDOFLINE;
}
return "";
}
#endregion
#region MakeContentDescription
private String MakeContentDescription()
{
return "";
}
#endregion
}
}
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System.Reflection;
using System.Runtime.CompilerServices;
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly: AssemblyTitle("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
//
// In order to sign your assembly you must specify a key to use. Refer to the
// Microsoft .NET Framework documentation for more information on assembly signing.
//
// Use the attributes below to control which key is used for signing.
//
// Notes:
// (*) If no key is specified, the assembly is not signed.
// (*) KeyName refers to a key that has been installed in the Crypto Service
// Provider (CSP) on your machine. KeyFile refers to a file which contains
// a key.
// (*) If the KeyFile and the KeyName values are both specified, the
// following processing occurs:
// (1) If the KeyName can be found in the CSP, that key is used.
// (2) If the KeyName does not exist and the KeyFile does exist, the key
// in the KeyFile is installed into the CSP and used.
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
// When specifying the KeyFile, the location of the KeyFile should be
// relative to the project output directory which is
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
// located in the project directory, you would specify the AssemblyKeyFile
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
// documentation for more information on this.
//
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]
@@ -0,0 +1,220 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectType>Local</ProjectType>
<ProductVersion>7.10.3077</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{6FBB299F-81A1-49EA-B00A-E916F8F797B3}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ApplicationIcon />
<AssemblyKeyContainerName />
<AssemblyName>DotNetOpenMail</AssemblyName>
<AssemblyOriginatorKeyFile />
<DefaultClientScript>JScript</DefaultClientScript>
<DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
<DefaultTargetSchema>IE50</DefaultTargetSchema>
<DelaySign>false</DelaySign>
<OutputType>Library</OutputType>
<RootNamespace>DotNetOpenMail</RootNamespace>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<StartupObject />
<FileUpgradeFlags>
</FileUpgradeFlags>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>0.0</OldToolsVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>bin\Debug\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile />
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>DotNetOpenMail.xml</DocumentationFile>
<DebugSymbols>true</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn />
<Optimize>false</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>full</DebugType>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<OutputPath>bin\Release\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile />
<DefineConstants>TRACE</DefineConstants>
<DocumentationFile>DotNetOpenMail.xml</DocumentationFile>
<DebugSymbols>false</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn />
<Optimize>true</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>none</DebugType>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System">
<Name>System</Name>
</Reference>
<Reference Include="System.Data">
<Name>System.Data</Name>
</Reference>
<Reference Include="System.Xml">
<Name>System.XML</Name>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AbstractEmailAttachment.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="EhloSmtpResponse.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="EmailAddress.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="EmailAddressCollection.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="EmailMessage.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Encoding\Base64Encoder.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Encoding\DoNothingEncoder.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Encoding\EightBitEncoder.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Encoding\EncoderFactory.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Encoding\EncodingType.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Encoding\IEncoder.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Encoding\QPEncoder.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Encoding\SevenBitEncoder.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="FileAttachment.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="HtmlAttachment.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="IEmailStringable.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="ISendableMessage.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="ISmtpProxy.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Logging\Logger.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Logging\LogMessage.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="MailException.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="MessageHeader.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="MessageHeaderCollection.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="MimeBoundary.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="MimeContainer.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="RawEmailMessage.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Resources\ARM.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="RFC2822Date.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SmtpAuth\ISmtpAuthToken.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SmtpAuth\LoginAuthToken.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SmtpAuth\SmtpAuthFactory.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SmtpAuth\SmtpAuthToken.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SmtpException.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SmtpProxy.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SmtpResponse.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SmtpResponseCode.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SmtpServer.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TextAttachment.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Utils\BinaryStreamUtil.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Utils\Configuration.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Utils\EmailAddressParser.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Utils\VersionInfo.cs">
<SubType>Code</SubType>
</Compile>
<EmbeddedResource Include="Resources\DotNetOpenMail.resx" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent />
<PostBuildEvent />
</PropertyGroup>
</Project>
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<LastOpenVersion>7.10.3077</LastOpenVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ReferencePath>C:\Visual Studio Projects\DotNetOpenMail\lib\</ReferencePath>
<CopyProjectDestinationFolder />
<CopyProjectUncPath />
<CopyProjectOption>0</CopyProjectOption>
<ProjectView>ShowAllFiles</ProjectView>
<ProjectTrust>0</ProjectTrust>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<EnableASPDebugging>false</EnableASPDebugging>
<EnableASPXDebugging>false</EnableASPXDebugging>
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
<EnableSQLServerDebugging>false</EnableSQLServerDebugging>
<RemoteDebugEnabled>false</RemoteDebugEnabled>
<RemoteDebugMachine />
<StartAction>Project</StartAction>
<StartArguments />
<StartPage />
<StartProgram />
<StartURL />
<StartWorkingDirectory />
<StartWithIE>true</StartWithIE>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<EnableASPDebugging>false</EnableASPDebugging>
<EnableASPXDebugging>false</EnableASPXDebugging>
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
<EnableSQLServerDebugging>false</EnableSQLServerDebugging>
<RemoteDebugEnabled>false</RemoteDebugEnabled>
<RemoteDebugMachine />
<StartAction>Project</StartAction>
<StartArguments />
<StartPage />
<StartProgram />
<StartURL />
<StartWorkingDirectory />
<StartWithIE>true</StartWithIE>
</PropertyGroup>
</Project>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,80 @@
using System;
using System.Collections;
using DotNetOpenMail.SmtpAuth;
namespace DotNetOpenMail
{
/// <summary>
/// The server response from EHLO
/// </summary>
public class EhloSmtpResponse
{
private int _responseCode=0;
private String _message;
ArrayList smtpAuthTypes=new ArrayList();
/// <summary>
/// Create an instance of the EhloSmtpResponse class
/// </summary>
public EhloSmtpResponse()
{
}
/// <summary>
/// Get the available Auth Types strings
/// as reported by the server.
/// (e.g. "login", etc.)
/// </summary>
/// <returns></returns>
public String[] GetAvailableAuthTypes()
{
String[] stringArray=new String[smtpAuthTypes.Count];
smtpAuthTypes.CopyTo(stringArray);
return stringArray;
//return (SmtpAuthType[]) smtpAuthTypes.ToArray(typeof (SmtpAuthType[]));
}
/// <summary>
/// Add an Auth type (by string as contained in the
/// EHLO authentication. These are converted to lower
/// case.
/// </summary>
/// <param name="authType">The auth type from EHLO</param>
public void AddAvailableAuthType(String authType)
{
smtpAuthTypes.Add(authType.Trim().ToLower());
}
/*
/// <summary>
/// Add an Auth type
/// </summary>
/// <param name="smtpAuthType"></param>
public void AddAvailableAuthType(SmtpAuthType smtpAuthType)
{
smtpAuthTypes.Add(smtpAuthType);
}
*/
/// <summary>
/// The SMTP Reponse code
/// </summary>
public int ResponseCode
{
get { return _responseCode; }
set { _responseCode=value; }
}
/// <summary>
/// The SMTP Message. This will be "OK" if successful,
/// otherwise it will be the part that failed.
/// </summary>
public String Message
{
get { return _message; }
set { _message=value; }
}
}
}
@@ -0,0 +1,205 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using DotNetOpenMail.Encoding;
namespace DotNetOpenMail
{
/// <summary>
/// An email address.
/// The two parts of the email address object
/// are the email address itself and the
/// name. The name may be encoded if desired.
/// </summary>
public class EmailAddress : IEmailStringable
{
private String _email=null;
private String _name=null;
private System.Text.Encoding _charset;
private Encoding.EncodingType _encodingtype=Encoding.EncodingType.QuotedPrintable;
#region EmailAddress
/// <summary>
/// Create an instance of an email address object.
/// </summary>
/// <param name="email">The address portion of the email</param>
/// <param name="name">The name portion of the email.</param>
public EmailAddress(String email, String name)
{
if (email!=null)
{
email=email.Trim();
}
this._email=email;
this._name=name;
}
#endregion
#region EmailAddress
/// <summary>
/// Create an instance of an email address object.
/// </summary>
/// <param name="email">The address portion of the email</param>
public EmailAddress(String email)
{
if (email!=null)
{
email=email.Trim();
}
else
{
email="";
}
this._email=email;
}
#endregion
#region EmailAddress
/// <summary>
/// Create an character-encoded instance of an email address object.
/// </summary>
/// <param name="email">The address portion of the email</param>
/// <param name="name">The name portion of the email.</param>
/// <param name="charset">The character set to encode the name portion of the email address.</param>
/// <param name="encodingtype">The encoding type to use to encode the name portion of the mail address.</param>
public EmailAddress(String email, String name, Encoding.EncodingType encodingtype, System.Text.Encoding charset)
{
if (email!=null)
{
email=email.Trim();
}
this._email=email;
this._name=name;
this._charset=charset;
this._encodingtype=encodingtype;
}
#endregion
#region Email
/// <summary>
/// The email address portion of the email address object
/// </summary>
public String Email
{
get {return _email;}
}
#endregion
#region Name
/// <summary>
/// The name portion of the email address object
/// </summary>
public String Name
{
get {return _name;}
}
#endregion
#region QuoteSpecials
private String QuoteSpecials(String str)
{
StringBuilder sb=new StringBuilder();
bool needsQuotes=false;
for (int i=0; i< str.Length; i++)
{
char ch=str[i];
if (ch=='\"')
{
needsQuotes=true;
sb.Append('\\');
}
else if (ch=='(' || ch==')' ||
ch=='<' || ch=='>' ||
ch==']' || ch=='[' ||
ch==':' || ch==';' ||
ch=='@' || ch=='\\' ||
ch==',' || ch=='.')
{
needsQuotes=true;
}
sb.Append(ch);
}
if (needsQuotes)
{
return "\""+sb.ToString()+"\"";
}
else
{
return sb.ToString();
}
}
#endregion
#region ToDataString
/// <summary>
/// Create the string representation of this email address
/// (encoded or otherwise) as it will appear in the email
/// </summary>
/// <returns></returns>
public String ToDataString()
{
if (_name!=null && _name.Trim()!="")
{
IEncoder encoder=Encoding.EncoderFactory.GetEncoder(_encodingtype);
System.Text.Encoding thecharset=_charset;
if (thecharset==null)
{
thecharset=Utils.Configuration.GetInstance().GetDefaultCharset();
}
String encodedname=encoder.EncodeHeaderString("", QuoteSpecials(Name.Trim()), thecharset, false);
return encodedname+" <"+Email+">";
}
else
{
return "<"+Email+">";
}
}
#endregion
#region ToString
/// <summary>
/// Calls ToDataString.
/// </summary>
/// <returns></returns>
public override String ToString()
{
return ToDataString();
}
#endregion
}
}
@@ -0,0 +1,151 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.Collections;
using DotNetOpenMail.Encoding;
namespace DotNetOpenMail
{
/// <summary>
/// A collection of EmailAddress objects. Implements
/// CollectionBase
/// </summary>
public class EmailAddressCollection : CollectionBase
{
/// <summary>
/// Create a new instance of the EmailAddressCollection
/// </summary>
public EmailAddressCollection()
{
}
#region Add
/// <summary>
/// Add an object to the collection
/// </summary>
/// <param name="emailaddress">The EmailAddress object to add</param>
/// <returns></returns>
public int Add( EmailAddress emailaddress )
{
return( List.Add( emailaddress ) );
}
#endregion
#region Add
/// <summary>
/// Append a collection of objects to the existing collection
/// </summary>
/// <param name="emailaddresses">The EmailAddressCollection to append to the existing collection.</param>
public void AddCollection( EmailAddressCollection emailaddresses )
{
foreach (EmailAddress emailaddress in emailaddresses)
{
List.Add(emailaddress);
}
}
#endregion
#region IndexOf
/// <summary>
/// Find the index of the EmailAddress in the collection
/// </summary>
/// <param name="value">The object to find.</param>
/// <returns>The index, from 0, or -1 if not found.</returns>
public int IndexOf( EmailAddress value )
{
return( List.IndexOf( value ) );
}
#endregion
#region Insert
/// <summary>
/// Insert an EmailAddress into the collection at the
/// specified index.
/// </summary>
/// <param name="index">The index, starting at zero.</param>
/// <param name="emailaddress">The email address to add to the collection</param>
public void Insert( int index, EmailAddress emailaddress )
{
List.Insert( index, emailaddress );
}
#endregion
#region Remove
/// <summary>
/// Remove an address, if found, from the collection.
/// </summary>
/// <param name="emailaddress">The EmailAddress to remove</param>
public void Remove( EmailAddress emailaddress )
{
List.Remove( emailaddress );
}
#endregion
#region ToDataString
/// <summary>
/// Render the email addresses in a comma-separated list,
/// suitable for being rendered in an email.
/// </summary>
/// <returns></returns>
public String ToDataString()
{
StringBuilder sb=new StringBuilder();
bool doneone=false;
foreach (EmailAddress emailaddress in List)
{
if (!doneone)
{
doneone=true;
}
else
{
sb.Append(", ");
}
sb.Append(emailaddress.ToDataString());
}
return sb.ToString();
}
#endregion
#region ToString
/// <summary>
/// Calls ToDataString().
/// </summary>
/// <returns></returns>
public override String ToString()
{
return ToDataString();
}
#endregion
}
}
@@ -0,0 +1,675 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections;
using System.Text;
using DotNetOpenMail.Resources;
using DotNetOpenMail.Utils;
using DotNetOpenMail.Encoding;
//using log4net;
namespace DotNetOpenMail
{
/// <summary>
/// An Email Message
/// </summary>
public class EmailMessage : ISendableMessage
{
#region variables
//private static readonly ILog log = LogManager.GetLogger(typeof(EmailMessage));
private String _subject=null;
private String _organization=null;
private String _bodytext=null;
private EmailAddress _fromaddress=null;
private EmailAddressCollection _toaddresses=new EmailAddressCollection();
private EmailAddressCollection _ccaddresses=new EmailAddressCollection();
private EmailAddressCollection _bccaddresses=new EmailAddressCollection();
private EmailAddress _envelopefromaddress=null;
private String _contenttype;
private MimeBoundary _mimeboundary;
private TextAttachment _textpart=null;
private HtmlAttachment _htmlpart=null;
private String _xmailer=null;
private ArrayList _mixedfileattachments=new ArrayList();
private ArrayList _relatedfileattachments=new ArrayList();
private MessageHeaderCollection _custommessageheaders=new MessageHeaderCollection();
private System.Text.Encoding _charset;
private Encoding.EncodingType _encodingtype=Encoding.EncodingType.QuotedPrintable;
#endregion
#region EmailMessage
/// <summary>
/// Create a new instance of an EmailMessage.
/// </summary>
public EmailMessage()
{
_mimeboundary=new MimeBoundary();
_charset=System.Text.Encoding.GetEncoding(Configuration.GetInstance().GetDefaultEncoding("iso-8859-1"));
_bodytext=GetNoMimeMessage();
}
#endregion
#region Subject
/// <summary>
/// The subject line or subject header of the
/// email.
/// </summary>
public String Subject
{
get {return _subject;}
set {_subject=value;}
}
#endregion
#region FromAddress
/// <summary>
/// The address that appears in the From header. It will
/// also be used as the Envelope From address in the SMTP
/// negotiation, unless it is overridden by the EnvelopeFromAddress
/// setting.
/// </summary>
public EmailAddress FromAddress
{
get {return _fromaddress;}
set {_fromaddress=value;}
}
#endregion
#region EnvelopeFromAddress
/// <summary>
/// Normally the FromAddress is used as the
/// envelope-from address, but it can be
/// overridden here, if it is not null.
/// </summary>
public EmailAddress EnvelopeFromAddress
{
get {return _envelopefromaddress;}
set {_envelopefromaddress=value;}
}
#endregion
#region AddToAddress
/// <summary>
/// Add a To address to the Headers. This will also
/// be used during the "RCPT TO" SMTP negotiation
/// </summary>
/// <param name="emailaddress">Email Address object of the recipient</param>
public void AddToAddress(EmailAddress emailaddress)
{
_toaddresses.Add(emailaddress);
}
/// <summary>
/// Add a To address to the Headers. This will also
/// be used during the "RCPT TO" SMTP negotiation
/// </summary>
/// <param name="email">The plain email address (don't include the name)</param>
public void AddToAddress(String email)
{
_toaddresses.Add(new EmailAddress(email));
}
#endregion
#region ToAddresses
/// <summary>
/// Retrieve the collection of recipients
/// that will appear in the "To" header of the
/// email.
/// </summary>
public EmailAddressCollection ToAddresses
{
get {return _toaddresses;}
}
#endregion
#region AddCcAddress
/// <summary>
/// Add a Cc address to the Headers. This will also
/// be used during the "RCPT TO" SMTP negotiation
/// </summary>
/// <param name="emailaddress">Email Address object of the recipient</param>
public void AddCcAddress(EmailAddress emailaddress)
{
_ccaddresses.Add(emailaddress);
}
/// <summary>
/// Add a Cc address to the Headers. This will also
/// be used during the "RCPT TO" SMTP negotiation
/// </summary>
/// <param name="email">The plain email address (don't include the name)</param>
public void AddCcAddress(String email)
{
_ccaddresses.Add(new EmailAddress(email));
}
#endregion
#region CcAddresses
/// <summary>
/// Retrieve the collection of recipients
/// that will appear in the "Cc" header of the
/// email.
/// </summary>
public EmailAddressCollection CcAddresses
{
get {return _ccaddresses;}
}
#endregion
#region AddBccAddress
/// <summary>
/// Add a recipient who will be "Blind Carbon Copied"
/// as a recipient of the email. BCC addresses are
/// not added to the email headers, but only appear
/// during the "RCPT TO" SMTP negotiation.
/// </summary>
/// <param name="emailaddress">The EmailAddress object</param>
public void AddBccAddress(EmailAddress emailaddress)
{
_bccaddresses.Add(emailaddress);
}
/// <summary>
/// Add a recipient who will be "Blind Carbon Copied"
/// as a recipient of the email. BCC addresses are
/// not added to the email headers, but only appear
/// during the "RCPT TO" SMTP negotiation.
/// </summary>
/// <param name="email">The plain email address (don't include the name)</param>
public void AddBccAddress(String email)
{
_bccaddresses.Add(new EmailAddress(email));
}
#endregion
#region BccAddresses
/// <summary>
/// Get the current EmailAddressCollection of BCC addresses
/// </summary>
public EmailAddressCollection BccAddresses
{
get {return _bccaddresses;}
}
#endregion
#region Organization
/// <summary>
/// Get/set the organization (as it will appear in the organization
/// header
/// </summary>
public String Organization
{
get {return _organization;}
set {_organization=value;}
}
#endregion
#region XMailer
/// <summary>
/// Get the current XMailer setting for the X-Mailer header.
/// </summary>
public String XMailer
{
get {return this._xmailer;}
set {this._xmailer=value;}
}
#endregion
#region AddCustomHeader
/// <summary>
/// Add a custom mail header, e.g. "X-MyHeader".
/// </summary>
/// <param name="header">The header name (without a colon)</param>
/// <param name="val">The value of the header. This value will not
/// be encoded.</param>
public void AddCustomHeader(String header, String val)
{
_custommessageheaders.Add(new MessageHeader(header, val));
}
#endregion
#region HeaderCharSet
/// <summary>
/// The charset that is used for encoding the headers
/// </summary>
public System.Text.Encoding HeaderCharSet
{
get {return _charset;}
set {_charset=value;}
}
#endregion
#region HeaderEncoding
/// <summary>
/// The mime encoding that is used for encoding the headers
/// </summary>
public Encoding.EncodingType HeaderEncoding
{
get {return this._encodingtype;}
set {_encodingtype=value;}
}
#endregion
#region GetStandardHeaders
/// <summary>
/// Get the minimal header set in the specified character,
/// and using the mime encoder provided.
/// </summary>
private MessageHeaderCollection GetStandardHeaders(System.Text.Encoding charset, IEncoder encoder)
{
MessageHeaderCollection standardheaders=new MessageHeaderCollection();
standardheaders.Add(new MessageHeader("From", _fromaddress.ToDataString()));
standardheaders.Add(new MessageHeader("To", _toaddresses.ToDataString()));
if (_ccaddresses.Count>0)
{
standardheaders.Add(new MessageHeader("Cc", _ccaddresses.ToString()));
}
//if (_bccaddresses.Count>0)
//{
//standardheaders.Add(new MessageHeader("Bcc", _bccaddresses.ToString()));
//}
String subject=_subject;
if (subject==null || subject.Trim()=="")
{
subject=EncodeHeaderValue("Subject", ARM.GetInstance().GetString("no_subject"));
}
standardheaders.Add(new MessageHeader("Subject", EncodeHeaderValue("Subject", subject)));
standardheaders.Add(new MessageHeader("Date", new RFC2822Date(DateTime.Now, TimeZone.CurrentTimeZone).ToString()));
if (!HasBodyTextOnly())
{
standardheaders.Add(new MessageHeader("MIME-Version", "1.0"));
}
#region X-Mailer Header
if (_xmailer!=null)
{
standardheaders.Add(new MessageHeader("X-Mailer", _xmailer));
}
else
{
String xmailer=Configuration.GetInstance().GetXSender();
if (xmailer!=null)
{
standardheaders.Add(new MessageHeader("X-Mailer", xmailer));
}
else
{
standardheaders.Add(new MessageHeader("X-Mailer", "DotNetOpenMail "+VersionInfo.GetInstance().ToString()));
}
}
#endregion
String contentType=null;
if (HasBodyTextOnly())
{
// ignore the mime stuff for now
}
else
{
if (HasMixedContent())
{
contentType="multipart/mixed;"+SmtpProxy.ENDOFLINE+
" boundary=\""+_mimeboundary.BoundaryString+"\"";
}
else if (HasRelatedContent())
{
contentType="multipart/related;"+SmtpProxy.ENDOFLINE+
" boundary=\""+_mimeboundary.BoundaryString+"\"";
}
else
{
contentType="multipart/alternative;"+SmtpProxy.ENDOFLINE+
" boundary=\""+_mimeboundary.BoundaryString+"\"";
}
// note: see http://www.faqs.org/rfcs/rfc2045.html , part 6.4
//contentType+=" charset=\""+charset.BodyName+"\"";
standardheaders.Add(new MessageHeader("Content-Type", contentType));
//standardheaders.Add(new MessageHeader("Content-Transfer-Encoding", encoder.ContentTransferEncodingString));
}
return standardheaders;
}
#endregion
#region EncodeHeaderValue
/// <summary>
/// Encode a header value using the current header encoder and charset.
/// </summary>
/// <param name="name">The header name</param>
/// <param name="val">The header value</param>
/// <returns></returns>
private String EncodeHeaderValue(String name, String val)
{
IEncoder encoder=Encoding.EncoderFactory.GetEncoder(this.HeaderEncoding);
return encoder.EncodeHeaderString(name, val, this.HeaderCharSet, false);
}
#endregion
#region HasMixedContent
/// <summary>
/// Returns true if there is content that should be "multipart/mixed"
/// </summary>
/// <returns>true if the content is multipart/mixed.</returns>
private bool HasMixedContent()
{
return (_mixedfileattachments.Count > 0);
}
#endregion
#region HasRelatedContent
/// <summary>
/// Returns true if there is content that should be "multipart/related"
/// </summary>
/// <returns>true if the content is multipart/related.</returns>
private bool HasRelatedContent()
{
return (_relatedfileattachments.Count > 0);
}
#endregion
#region ToDataStringHeaders
/// <summary>
/// Encode the headers as they will appear in the email
/// </summary>
/// <param name="charset">the charset encoding for the string</param>
/// <param name="encoder">the mime encoding</param>
/// <returns>the encoded string</returns>
internal String ToDataStringHeaders(System.Text.Encoding charset, IEncoder encoder)
{
StringBuilder sb=new StringBuilder();
MessageHeaderCollection standardheaders=GetStandardHeaders(charset, encoder);
sb.Append(standardheaders.ToDataString());
if (_custommessageheaders.Count > 0)
{
sb.Append(_custommessageheaders.ToDataString());
}
return sb.ToString();
}
#endregion
#region HasBodyTextOnly
private bool HasBodyTextOnly()
{
return (_textpart==null
&& _htmlpart==null
&& !HasMixedContent()
&& !HasRelatedContent());
}
#endregion
#region ToDataStringBody
/// <summary>
/// Encode the email body as it will appear in the email
/// </summary>
/// <returns>the encoded body</returns>
internal String ToDataStringBody()
{
bool mixedistop=false;
bool relatedistop=false;
bool alternativeistop=false;
if (HasBodyTextOnly())
{
return FormatBodyText(_bodytext);
}
MimeBoundary relatedcontentmimeboundary=null;
MimeBoundary mixedcontentmimeboundary=null;
MimeBoundary altertnativecontentmimeboundary=null;
#region Determine which uses the top-level boundary
if (HasMixedContent())
{
mixedistop=true;
mixedcontentmimeboundary=_mimeboundary;
relatedcontentmimeboundary=new MimeBoundary();
altertnativecontentmimeboundary=new MimeBoundary();
}
else if (HasRelatedContent())
{
relatedistop=true;
relatedcontentmimeboundary=_mimeboundary;
altertnativecontentmimeboundary=new MimeBoundary();
}
else
{
alternativeistop=true;
altertnativecontentmimeboundary=_mimeboundary;
}
#endregion
MimeContainer alternativemimecontainer=new MimeContainer(altertnativecontentmimeboundary, "multipart/alternative", alternativeistop);
MimeContainer topcontainer=alternativemimecontainer;
#region Text & HTML Parts
if (_textpart!=null)
{
alternativemimecontainer.AddAttachment(_textpart);
}
if (_htmlpart!=null)
{
alternativemimecontainer.AddAttachment(_htmlpart);
}
#endregion
#region Related Content
if (HasRelatedContent())
{
//topcontainer=new MimeContainer(relatedcontentmimeboundary, "multipart/related", relatedistop);
topcontainer=new MimeContainer(relatedcontentmimeboundary, "multipart/related;\r\n type=\"multipart/alternative\"", relatedistop);
topcontainer.AddMimeContainer(alternativemimecontainer);
foreach (FileAttachment attachment in _relatedfileattachments)
{
topcontainer.AddAttachment(attachment);
}
}
#endregion
#region Mixed Content
if (HasMixedContent())
{
MimeContainer oldtopcontainer=topcontainer;
topcontainer=new MimeContainer(mixedcontentmimeboundary, "multipart/mixed", mixedistop);
topcontainer.AddMimeContainer(oldtopcontainer);
foreach (FileAttachment attachment in _mixedfileattachments)
{
topcontainer.AddAttachment(attachment);
}
}
#endregion
if (_bodytext==null)
{
return topcontainer.ToDataString();
}
else
{
return FormatBodyText(_bodytext)+".\r\n\r\n"
+topcontainer.ToDataString();
}
}
#endregion
#region FormatBodyText
/// <summary>
/// format the body text---not implemented yet.
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
private String FormatBodyText(String text)
{
return text;
}
#endregion
#region GetNoMimeMessage
private String GetNoMimeMessage()
{
return ARM.GetInstance().GetString("this_is_mime");
}
#endregion
/// <summary>
/// The text that occurs within the body. By default,
/// it is a MIME notice, but it can be overridden here.
/// NOTE: This is only useful for 7 bit us-ascii currently.
/// </summary>
public String BodyText
{
get { return _bodytext;}
set { _bodytext=value;}
}
#region ToDataString
/// <summary>
/// Render the encoded message for smtp "DATA" transmission.
/// This is the final version that will get sent to the
/// </summary>
/// <returns></returns>
public String ToDataString()
{
IEncoder encoder=EncoderFactory.GetEncoder(HeaderEncoding);
return ToDataStringHeaders(this.HeaderCharSet, encoder)+SmtpProxy.ENDOFLINE+ToDataStringBody();
}
#endregion
#region Send
/// <summary>
/// Send out the email via the smtp server given. If
/// the SMTP server throws an error, an SmtpException will
/// be thrown. All other exceptions will be MailExceptions
/// </summary>
/// <param name="smtpserver">The outgoing SMTP server.</param>
/// <returns>true if sent successfully. (note that this
/// will not currently return false, but in the future
/// a false value may be used)</returns>
public bool Send(SmtpServer smtpserver)
{
//SmtpProxy smtpproxy=smtpserver.GetSmtpProxy();
if(_fromaddress == null)
{
throw new MailException(ARM.GetInstance().GetString("error_no_from"));
}
EmailAddress envelopefrom=_envelopefromaddress;
if (envelopefrom==null)
{
envelopefrom=_fromaddress;
}
EmailAddressCollection allrecipients=new EmailAddressCollection();
allrecipients.AddCollection(_toaddresses);
allrecipients.AddCollection(_ccaddresses);
allrecipients.AddCollection(_bccaddresses);
return smtpserver.Send(this, allrecipients, envelopefrom);
}
#endregion
#region ContentType
/// <summary>
/// Set the content type string in the mime header
/// </summary>
public String ContentType
{
get {return _contenttype;}
set {_contenttype=value;}
}
#endregion
#region TextPart
/// <summary>
/// Set the plain text part of the email. This is optional
/// </summary>
public TextAttachment TextPart
{
set {_textpart=value;}
get {return _textpart;}
}
#endregion
#region HtmlPart
/// <summary>
/// Set the html part of the email. This is optional
/// </summary>
public HtmlAttachment HtmlPart
{
set {_htmlpart=value;}
get {return _htmlpart;}
}
#endregion
#region AddMixedAttachment
/// <summary>
/// Add an attachment which will appear to the user as
/// a separate file. (It is not referred to in the email itself.)
/// </summary>
/// <param name="fileattachment">The file attachment</param>
public void AddMixedAttachment(FileAttachment fileattachment)
{
_mixedfileattachments.Add(fileattachment);
}
#endregion
#region AddRelatedAttachment
/// <summary>
/// Add an image which is referred to from another part of
/// the email (probably the HTML attachment). You should
/// set the ContentID of the file attachment before passing
/// it in.
/// </summary>
/// <param name="fileattachment">The file attachment</param>
public void AddRelatedAttachment(FileAttachment fileattachment)
{
_relatedfileattachments.Add(fileattachment);
}
#endregion
}
}
@@ -0,0 +1,221 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.IO;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// Encode a file in Base64 Encoding.
///
/// See: http://www.freesoft.org/CIE/RFC/1521/7.htm
/// </summary>
public class Base64Encoder : IEncoder
{
/// <summary>
/// The maximum chars per line before end of line char(s)
/// </summary>
public static readonly int MAX_CHARS_PER_LINE=76;
/// <summary>
/// The end-of-line character(s) to use
/// </summary>
public static readonly String END_OF_LINE="\r\n";
#region Base64Encoder
/// <summary>
/// Empty Constructor
/// </summary>
private Base64Encoder()
{
}
#endregion
#region GetInstance
/// <summary>
/// Create an instance of this class
/// </summary>
public static Base64Encoder GetInstance()
{
return new Base64Encoder();
}
#endregion
#region Encode
/// <summary>
/// Encode the Stringreader's data in base64.
///
/// Note: This is not particularly efficient on memory.
/// This method should probably be improved to
/// take advantage of the Reader, rather than
/// taking the whole string into memory.
/// </summary>
/// <param name="stringreader">Reader for incoming string</param>
/// <param name="stringwriter">Writer for outgoing encoded string</param>
/// <param name="encoding">The character encoding for the encoded string.</param>
public void Encode(StringReader stringreader, StringWriter stringwriter, System.Text.Encoding encoding)
{
try
{
String sourceString=stringreader.ReadToEnd();
stringwriter.Write(EncodeString(sourceString, encoding));
}
catch(Exception e)
{
throw new Exception("Error in base64Encode" + e.Message);
}
}
#endregion
#region Encode
/// <summary>
/// Encode the File's data in base64.
/// </summary>
/// <param name="filestream">Reader for incoming string</param>
/// <param name="stringwriter">Writer for outgoing encoded string</param>
/// <param name="charset">The character set for the encoded string</param>
public void Encode(FileStream filestream, StringWriter stringwriter, System.Text.Encoding charset)
{
//fs = finfo.OpenRead();
byte[] buffer = new byte[filestream.Length];
filestream.Read(buffer, 0, buffer.Length);
filestream.Close();
stringwriter.Write(MakeLines(System.Convert.ToBase64String(buffer, 0, buffer.Length)));
//Encode(new StringReader(System.Text.Encoding.ASCII.GetString(buffer)), stringwriter);
}
#endregion
#region Encode
/// <summary>
/// Encode the File's data in base64.
/// </summary>
/// <param name="binaryreader">Reader for incoming string</param>
/// <param name="stringwriter">Writer for outgoing encoded string</param>
public void Encode(BinaryReader binaryreader, StringWriter stringwriter)
{
//fs = finfo.OpenRead();
byte[] b;
int charstoread=Base64Encoder.MAX_CHARS_PER_LINE * 102;
while (true)
{
b = binaryreader.ReadBytes(charstoread);
if (b.Length > 0)
{
stringwriter.Write(MakeLines(Convert.ToBase64String(b)));
}
else
{
break;
}
}
//Encode(new StringReader(System.Text.Encoding.ASCII.GetString(buffer)), stringwriter);
}
#endregion
#region EncodeString
/// <summary>
/// Encode a string in Base64 in a particular characters set
/// </summary>
/// <param name="sourceString">The source text</param>
/// <param name="charset">the charset for the encoded text</param>
/// <returns>Returns an encoded string</returns>
public String EncodeString(String sourceString, System.Text.Encoding charset)
{
byte[] sourceBytes = new byte[sourceString.Length];
sourceBytes = charset.GetBytes(sourceString);
//sourceBytes = System.Text.Encoding.UTF8.GetBytes(sourceString);
String result=Convert.ToBase64String(sourceBytes);
return (MakeLines(result));
}
#endregion
#region EncodeHeaderString
/// <summary>
/// Encode header as per RFC 2047:
/// http://www.faqs.org/rfcs/rfc2047.html
/// </summary>
/// <param name="name">The header name</param>
/// <param name="val">The header text to be encoded (data only)</param>
/// <param name="charset">The charset for the encoded string</param>
/// <param name="forceencoding">ignored for this class</param>
/// <returns>Returns the encoded string</returns>
public String EncodeHeaderString(String name, String val, System.Text.Encoding charset, bool forceencoding)
{
String encodedtext=EncodeString(val, charset);
String tmp="=?"+charset.HeaderName+"?B?"+encodedtext+"?=";
return tmp;
}
#endregion
#region MakeLines
/// <summary>
/// Chop the text into lines that are smaller
/// than MAX_CHARS_PER_LINE
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
private String MakeLines(String source)
{
StringBuilder sb=new StringBuilder();
int pos=0;
for (int i=0; i<source.Length; i++)
{
sb.Append(source[i]);
pos++;
if (pos>=Base64Encoder.MAX_CHARS_PER_LINE)
{
sb.Append(Base64Encoder.END_OF_LINE);
pos=0;
}
}
return sb.ToString();
}
#endregion
#region ContentTransferEncodingString
/// <summary>
/// The String that goes in the content transfer encoding header
/// </summary>
public String ContentTransferEncodingString
{
get {return "base64";}
}
#endregion
}
}
@@ -0,0 +1,96 @@
using System;
using System.Text;
using System.IO;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// An encoder that does nothing. (This is essentially
/// what the 7bit and 8bit encodings are; they are just
/// markers, not actual encodings)
/// </summary>
public abstract class DoNothingEncoder : IEncoder
{
/// <summary>
/// Empty constructor
/// </summary>
public DoNothingEncoder()
{
}
#region Encode
/// <summary>
/// Echo the text back unchanged.
/// </summary>
/// <param name="stringreader">Reader for the incoming string</param>
/// <param name="stringwriter">Writer for the outgoing string</param>
/// <param name="encoding">The encodigng for the outgoing string (ignored)</param>
public void Encode(StringReader stringreader, StringWriter stringwriter, System.Text.Encoding encoding)
{
try
{
stringwriter.Write(stringreader.ReadToEnd());
}
catch(Exception e)
{
throw new Exception("Error writing during Encoding" + e.Message);
}
}
#endregion
#region Encode
/// <summary>
/// Echo the text back unchanged
/// </summary>
/// <param name="filestream">The incoming filestream</param>
/// <param name="stringwriter">The outgoing filestream</param>
/// <param name="charset">Charset (ignored)</param>
public void Encode(FileStream filestream, StringWriter stringwriter, System.Text.Encoding charset)
{
byte[] buffer = new byte[filestream.Length];
filestream.Read(buffer, 0, buffer.Length);
filestream.Close();
stringwriter.Write(buffer);
}
#endregion
#region Encode
/// <summary>
/// Echo the text back unchanged (good for 7bit text only).
/// </summary>
/// <param name="binaryreader">The incoming binaryreader</param>
/// <param name="stringwriter">The outgoing stream</param>
public void Encode(BinaryReader binaryreader, StringWriter stringwriter)
{
throw new Exception("Binary reader doesn't do anything for this reader");
//stringwriter.Write(binaryreader.ReadString());
}
#endregion
/// <summary>
/// Do nothing to the header string
/// </summary>
/// <param name="name">The header key</param>
/// <param name="val">The header value</param>
/// <param name="charset">The charset to encode in (ignored)</param>
/// <param name="forceencoding">(ignored)</param>
/// <returns></returns>
public String EncodeHeaderString(String name, String val, System.Text.Encoding charset, bool forceencoding)
{
return val;
}
#region ContentTransferEncodingString
/// <summary>
/// The String that goes in the content transfer encoding header
/// </summary>
public virtual String ContentTransferEncodingString
{
get {throw new ApplicationException("Implement this");}
}
#endregion
}
}
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.IO;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// Denotes 8bit encoding. Note that this doesn't really
/// encode anything; it just specifies that this email is already
/// in 8-bit encoding.
/// </summary>
public class EightBitEncoder : DoNothingEncoder
{
#region EightBitEncoder
/// <summary>
/// Empty Constructor
/// </summary>
private EightBitEncoder()
{
}
#endregion
#region GetInstance
/// <summary>
/// Create the EightBitEncoder object.
/// </summary>
public static EightBitEncoder GetInstance()
{
return new EightBitEncoder();
}
#endregion
#region ContentTransferEncodingString
/// <summary>
/// The String that goes in the content transfer encoding header
/// </summary>
public override String ContentTransferEncodingString
{
get {return "8bit";}
}
#endregion
}
}
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// Factory for instantiating the right encoder class,
/// given an encoding
/// </summary>
internal class EncoderFactory
{
/// <summary>
/// Empty Constructor.
/// </summary>
internal EncoderFactory()
{
}
/// <summary>
/// Method for determining the correct encoder for this
/// encoding type.
/// </summary>
/// <param name="encodingtype">Enumerated encoding type</param>
/// <returns>Returns the proper IEncoder implementation</returns>
/// <exception cref="ApplicationException">Throws an ApplicationException if the specified encoding is unknown.</exception>
public static IEncoder GetEncoder(EncodingType encodingtype)
{
if (encodingtype==EncodingType.Base64)
{
return Base64Encoder.GetInstance();
}
else if (encodingtype==EncodingType.QuotedPrintable)
{
return QPEncoder.GetInstance();
}
else if (encodingtype==EncodingType.SevenBit)
{
return SevenBitEncoder.GetInstance();
}
else if (encodingtype==EncodingType.EightBit)
{
return EightBitEncoder.GetInstance();
}
else
{
throw new ApplicationException("This encoder type is not implemented");
}
}
}
}
@@ -0,0 +1,27 @@
using System;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// Enumeration of encoding types.
/// </summary>
public enum EncodingType
{
/// <summary>
/// The Quoted-Printable encoding
/// </summary>
QuotedPrintable,
/// <summary>
/// The Base-65 encoding
/// </summary>
Base64,
/// <summary>
/// The 7Bit encoding marker
/// </summary>
SevenBit,
/// <summary>
/// The 8Bit encoding marker
/// </summary>
EightBit
}
}
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.IO;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// An interface for a string encoder
/// </summary>
public interface IEncoder
{
/// <summary>
/// Encode from the stringreader to the stringwriter.
/// </summary>
/// <param name="source">an open stringreader to the source string</param>
/// <param name="destination">where the output is written</param>
/// <param name="charset">the outgoing charset</param>
void Encode(StringReader source, StringWriter destination, System.Text.Encoding charset);
/// <summary>
/// Encode the file stream into the stringwriter.
/// </summary>
/// <param name="filestream">an open stream to file to be read</param>
/// <param name="destination">where the output is written</param>
/// <param name="charset">the outgoing charset</param>
void Encode(FileStream filestream, StringWriter destination, System.Text.Encoding charset);
/// <summary>
/// Encode the binary reader into the stringwriter.
/// </summary>
/// <param name="binaryreader">an open binary reader for the data to be encoded.</param>
/// <param name="destination">where the output is written</param>
void Encode(BinaryReader binaryreader, StringWriter destination);
/// <summary>
/// Encode the string according to rfc-2047 if some of it
/// falls outside the 7bit ASCII charset.
/// </summary>
/// <param name="name">The header key</param>
/// <param name="val">The header value string</param>
/// <param name="charset">Charset for the encoded string</param>
/// <param name="forceencoding">Force encoding, even if in ascii-only.</param>
/// <returns>The encoded string</returns>
String EncodeHeaderString(String name, String val, System.Text.Encoding charset, bool forceencoding);
/// <summary>
/// The String that goes in the content transfer encoding header
/// </summary>
String ContentTransferEncodingString {get;}
}
}
@@ -0,0 +1,446 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.IO;
//using log4net;
using DotNetOpenMail;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// See: http://www.freesoft.org/CIE/RFC/1521/6.htm
/// </summary>
public class QPEncoder : IEncoder
{
/// <summary>
/// Logger
/// </summary>
//private static readonly ILog log = LogManager.GetLogger(typeof(QPEncoder));
/// <summary>
/// Maximum characters per line, before the end-of-line character
/// </summary>
public static readonly int MAX_CHARS_PER_LINE=76;
/// <summary>
/// The end-of-line character(s).
/// </summary>
public static readonly String END_OF_LINE="\r\n";
#region QPEncoder
/// <summary>
/// Empty Constructor
/// </summary>
private QPEncoder()
{
}
#endregion
#region GetInstance
/// <summary>
/// Create an instance of the encoder
/// </summary>
/// <returns>The instantiated Quoted-printable encoder</returns>
public static QPEncoder GetInstance()
{
return new QPEncoder();
}
#endregion
#region Encode
/// <summary>
/// Encode the incoming stream in quoted-printable encoding.
/// </summary>
/// <param name="binaryreader">The incoming binary reader</param>
/// <param name="stringwriter">The outgoing string writer</param>
public void Encode(BinaryReader binaryreader, StringWriter stringwriter)
{
throw new ApplicationException("Not Implemented Yet; use a base64 encoder instead.");
}
#endregion
#region Encode
/// <summary>
/// Encode the incoming stream in quoted-printable encoding.
/// </summary>
/// <param name="filestream">The incoming file stream</param>
/// <param name="stringwriter">The outgoing string writer</param>
/// <param name="charset">The charset to write the outgoing string in</param>
public void Encode(FileStream filestream, StringWriter stringwriter, System.Text.Encoding charset)
{
throw new ApplicationException("Not Implemented Yet; use a base64 encoder instead.");
}
#endregion
#region Encode
/// <summary>
/// Encode the string read by the stringreader into the
/// stringwriter. This implementation does not encode
/// the characters where encoding is optional, and does
/// not encode spaces or tabs (except at the end of a line).
///
/// Line breaks are converted to the RFC line break (CRLF).
// The last linebreak is not included, if any, but this
/// </summary>
/// <param name="stringreader">The incoming string reader</param>
/// <param name="stringwriter">The outgoing stringwriter</param>
/// <param name="charset">The outgoing charset for the string</param>
public void Encode(StringReader stringreader, StringWriter stringwriter, System.Text.Encoding charset)
{
Encode(stringreader, stringwriter, charset, false, 0);
}
#endregion
#region EncodeString
/// <summary>
/// Encode the string in quoted printable format
/// </summary>
/// <param name="str">The source string</param>
/// <param name="charset">The outgoing charset</param>
/// <returns>the encoded string</returns>
public String EncodeString(String str, System.Text.Encoding charset)
{
return EncodeString(str, charset, false, 0);
}
#endregion
#region EncodeString
/// <summary>
/// Encode the string in quoted printable format
/// </summary>
/// <param name="sourceString">The source string</param>
/// <param name="charset">The outgoing charset</param>
/// <param name="forceRFC2047">Force encoding, even if not required by qp RFC</param>
/// <param name="offset">The total characters outside the encoding. This is used to figure
/// out how long the line will be after encoding.</param>
/// <returns>the encoded string</returns>
public String EncodeString(String sourceString, System.Text.Encoding charset, bool forceRFC2047, int offset)
{
StringReader sr=new StringReader(sourceString);
StringBuilder sb=new StringBuilder();
StringWriter sw=new StringWriter(sb);
Encode(sr, sw, charset, forceRFC2047, offset);
return sb.ToString();
}
#endregion
#region EncodeHeaderString
/// <summary>
/// Encode header as per RFC 2047:
/// http://www.faqs.org/rfcs/rfc2047.html
///
/// </summary>
/// <remarks>This doesn't split long lines yet</remarks>
/// <param name="name">the header name</param>
/// <param name="val">the string to encode</param>
/// <param name="charset">The charset to encode to</param>
/// <param name="forceencoding">Force encoding, even if not required by qp RFC</param>
/// <returns>the encoded string, suitable for use in a header</returns>
public String EncodeHeaderString(String name, String val, System.Text.Encoding charset, bool forceencoding)
{
if (forceencoding || IsNonAscii(val))
{
String start="=?"+charset.HeaderName+"?Q?";
String end="?=";
int offset=name.Length+start.Length+end.Length+2; // the 2 is for the colon and space
String encodedtext=EncodeString(val, charset, true, offset);
//log.Debug("LINE BEFORE SPLIT IS "+encodedtext);
if (encodedtext.Length + offset > QPEncoder.MAX_CHARS_PER_LINE)
{
StringBuilder sb=new StringBuilder("");
foreach (String line in encodedtext.Split('\n'))
{
String tmp=line;
if (sb.Length>0)
{
sb.Append(QPEncoder.END_OF_LINE+" ");
}
tmp=line.TrimEnd(new char[] {'\r', '='});
//if (line.LastIndexOf("\r") == line.Length-1)
//{
//tmp=line.Substring(0, line.Length-1);
//}
sb.Append(start+tmp+end);
}
return sb.ToString();
}
else
{
return start+encodedtext+end;
}
}
else
{
return val;
}
}
#endregion
#region EncodeChar
/// <summary>
/// Encode a char according to quoted-printable
/// standard
/// </summary>
/// <param name="ch">the char to encode</param>
/// <returns>the encoded char representation</returns>
private String EncodeChar(char ch)
{
int intch=(int) ch;
if (intch > 255)
{
//log.Debug("encoding qp: "+String.Format("0x{0:X4}", intch));
int ch1=intch >> 8;
int ch2=intch & 0xff;
return String.Format("={0:X2}={1:X2}", ch1, ch2);
}
else
{
return String.Format("={0:X2}",(int) ch);
}
}
#endregion
#region EncodeByte
/// <summary>
/// Encode a byte according to quoted-printable
/// standard
/// </summary>
/// <param name="ch">the byte to encode</param>
/// <returns>the encoded byte representation</returns>
private String EncodeByte(byte ch)
{
return String.Format("={0:X2}",(int) ch);
}
#endregion
#region ContentTransferEncodingString
/// <summary>
/// The String that goes in the content transfer encoding header
/// </summary>
public String ContentTransferEncodingString
{
get {return "quoted-printable";}
}
#endregion
#region NeedsEncoding
/// <summary>
/// Return true if the char needs to be encoded.
/// </summary>
/// <param name="ch"></param>
/// <param name="forceRFC2047"></param>
/// <returns></returns>
internal bool NeedsEncoding(char ch, bool forceRFC2047)
{
if ((ch <= 0x1f && ch != 0x09) || // less than space (except tab)
ch == 0x3d || // equal sign
ch>= 0x7f // above 7bit
|| (forceRFC2047 && (ch==0x20 || ch==0x09 || ch==0x3f))
)
{
return true;
}
else
{
return false;
}
}
#endregion
#region NeedsEncoding
/// <summary>
/// Return true if the byte needs to be encoded.
/// </summary>
/// <param name="ch"></param>
/// <param name="forceRFC2047"></param>
/// <returns></returns>
internal bool NeedsEncoding(byte ch, bool forceRFC2047)
{
if ((ch <= 0x1f && ch != 0x09) || // less than space (except tab)
ch == 0x3d || // equal sign
ch>= 0x7f // above 7bit
|| (forceRFC2047 && (ch==0x20 || ch==0x09 || ch==0x3f))
)
{
return true;
}
else
{
return false;
}
}
#endregion
#region IsNonAscii
/// <summary>
/// Return true if the string needs to be encoded.
/// </summary>
/// <param name="str">The string to check</param>
/// <returns>true if outside 127-bit, or one of the
/// quoted-printable special characters.</returns>
internal bool IsNonAscii(String str)
{
for (int i=0; i<str.Length; i++)
{
if (IsNonAscii(str[i]))
{
return true;
}
}
return false;
}
#endregion
#region IsNonAscii
/// <summary>
/// Check if the character is one of the non-qp
/// characters
/// </summary>
/// <param name="ch">the character to check</param>
/// <returns>true if outside the acceptable qp range</returns>
internal bool IsNonAscii(char ch)
{
if ((ch <= 0x1f && ch != 0x09) || // less than space (except tab)
ch == 0x3d || // equal sign
ch>= 0x7f // above 7bit
)
{
return true;
}
else
{
return false;
}
}
#endregion
#region Encode
/// <summary>
/// Encode the string read by the stringreader into the
/// stringwriter. This implementation does not encode
/// the characters where encoding is optional, and does
/// not encode spaces or tabs (except at the end of a line).
///
/// Line breaks are converted to the RFC line break (CRLF).
// The last linebreak is not included, if any---although this
/// may change in the future.
/// </summary>
/// <param name="stringreader">The incoming string reader</param>
/// <param name="stringwriter">The outgoing stringwriter</param>
/// <param name="charset">The outgoing charset for the string</param>
/// <param name="forceRFC2047">If true, force the encoding of all the
/// <param name="offset">These are the number of characters that
/// will appear outside this string, e.g. the header name, etc.</param>
/// characters (not just those that are given in RFC2027).</param>
public void Encode(StringReader stringreader, StringWriter stringwriter, System.Text.Encoding charset, bool forceRFC2047, int offset)
{
if (offset > QPEncoder.MAX_CHARS_PER_LINE - 15)
{
throw new MailException("Invalid offset (header name is too long): "+offset);
}
String line=null;
bool forceencoding=false;
if (charset==null)
{
charset=Utils.Configuration.GetInstance().GetDefaultCharset();
}
while((line=stringreader.ReadLine())!=null)
{
int columnposition=0;
byte[] bytes=charset.GetBytes(line);
// see Rule #3 (spaces and tabs at end of line are encoded)
StringBuilder blankendchars=new StringBuilder("");
int endpos=bytes.Length-1;
while (endpos >=0 && (bytes[endpos]==0x20 || bytes[endpos]==0x09) )
{
blankendchars.Insert(blankendchars.Length, EncodeByte(bytes[endpos]));
endpos--;
}
for (int i=0; i<=endpos; i++)
{
String towrite="";
if (forceencoding || NeedsEncoding(bytes[i], forceRFC2047))
{
columnposition+=3;
towrite=EncodeByte(bytes[i]);
}
else
{
columnposition+=1;
// this is a single byte, so multibyte chars won't
// be affected by this.
towrite=charset.GetString(new byte[]{bytes[i]});
}
if (offset + columnposition > QPEncoder.MAX_CHARS_PER_LINE )
{
stringwriter.Write("="+QPEncoder.END_OF_LINE);
columnposition=0;
}
stringwriter.Write(towrite);
}
if (blankendchars.Length > 0)
{
if (offset+columnposition+blankendchars.Length > QPEncoder.MAX_CHARS_PER_LINE)
{
stringwriter.Write("="+QPEncoder.END_OF_LINE);
}
stringwriter.Write(blankendchars);
}
if (stringreader.Peek() >= 0)
{
stringwriter.Write("\r\n");
}
}
}
#endregion
}
}
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail.Encoding
{
/// <summary>
/// Denotes 7bit encoding. Note that this doesn't really
/// encode anything; it just specifies that this email is already
/// in 7-bit ascii encoding.
/// </summary>
public class SevenBitEncoder : DoNothingEncoder
{
/// <summary>
/// Empty constructor
/// </summary>
private SevenBitEncoder()
{
}
/// <summary>
/// Create an instance of this class.
/// </summary>
/// <returns></returns>
public static SevenBitEncoder GetInstance()
{
return new SevenBitEncoder();
}
#region ContentTransferEncodingString
/// <summary>
/// The String that goes in the content transfer encoding header
/// </summary>
public override String ContentTransferEncodingString
{
get {return "7bit";}
}
#endregion
}
}
@@ -0,0 +1,199 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
using System.IO;
//using log4net;
using DotNetOpenMail.Encoding;
namespace DotNetOpenMail
{
/// <summary>
/// A mime representation of a file which can be transferred
/// via email.
/// </summary>
public class FileAttachment : AbstractEmailAttachment
{
//private static readonly ILog log = LogManager.GetLogger(typeof(FileAttachment));
/// <summary>
/// Create a new File attachment from a FileInfo object
/// </summary>
/// <param name="fileinfo">A fileinfo object which points to a local file.</param>
public FileAttachment(FileInfo fileinfo) : this(fileinfo, null)
{
}
/// <summary>
/// Create a new text file attachment from a StreamReader.
/// </summary>
/// <param name="streamreader">An open streamreader</param>
public FileAttachment(StreamReader streamreader) : this(streamreader, null)
{
}
/// <summary>
/// Create a new binary file attachment from a BinaryReader.
/// </summary>
/// <param name="binaryreader">An open binaryreader</param>
public FileAttachment(BinaryReader binaryreader) : this(binaryreader, null)
{
}
/// <summary>
/// Create a new binary file attachment from an array of bytes.
/// </summary>
/// <param name="bytes">An array of bytes</param>
public FileAttachment(byte[] bytes) : this(bytes, null)
{
}
/// <summary>
/// Create a new file attachment from a String.
/// </summary>
/// <param name="content">The contents of the file</param>
public FileAttachment(String content) : this(content, null)
{
}
#region FileAttachment
/// <summary>
/// Create a new File attachment with a contentid from a FileInfo object.
/// The contentid will be used to refer to this attachment in
/// another mime part of the email.
/// </summary>
/// <param name="fileinfo">A fileinfo object which points to a local file.</param>
/// <param name="contentid">the content id value</param>
public FileAttachment(FileInfo fileinfo, String contentid)
{
this.ContentType="binary/octet-stream";
if (FileName==null)
{
FileName=fileinfo.Name;
}
this._fileinfo=fileinfo;
this._contentid=contentid;
this.CharSet=null;
//this.Contents=contents;
this.Encoding=EncodingType.Base64;
//this.Encoder=EncoderFactory.GetEncoder(EncoderFactory.GetEncoder(EncodingType);
}
#endregion
#region FileAttachment
/// <summary>
/// Create a new file attachment from a StreamReader.
/// The contentid will be used to refer to this attachment in
/// another mime part of the email.
/// </summary>
/// <param name="streamreader">An open streamreader</param>
/// <param name="contentid">the content id value</param>
public FileAttachment(StreamReader streamreader, String contentid)
{
if (this.ContentType==null)
{
this.ContentType="binary/octet-stream";
}
String tmp=streamreader.ReadToEnd();
streamreader.Close();
this.Contents=tmp;
this.CharSet=null;
this._contentid=contentid;
this.Encoding=EncodingType.Base64;
}
#endregion
#region FileAttachment
/// <summary>
/// Create a new file attachment from a BinaryReader.
/// The contentid will be used to refer to this attachment in
/// another mime part of the email.
/// </summary>
/// <param name="binaryreader">An open binary readerr</param>
/// <param name="contentid">the content id value</param>
public FileAttachment(BinaryReader binaryreader, String contentid)
{
if (this.ContentType==null)
{
this.ContentType="binary/octet-stream";
}
this._contentbytes=Utils.BinaryReaderUtil.ReadIntoByteArray(binaryreader);
binaryreader.Close();
this.CharSet=null;
this._contentid=contentid;
this.Encoding=EncodingType.Base64;
}
#endregion
#region FileAttachment
/// <summary>
/// Create a new file attachment from a byte array.
/// The contentid will be used to refer to this attachment in
/// another mime part of the email.
/// </summary>
/// <param name="bytes">An array of bytes</param>
/// <param name="contentid">the content id value</param>
public FileAttachment(byte[] bytes, String contentid)
{
if (this.ContentType==null)
{
this.ContentType="binary/octet-stream";
}
this.ContentBytes=bytes;
this.CharSet=null;
this.Encoding=EncodingType.Base64;
}
#endregion
/// <summary>
/// Create a new text file attachment from a String.
/// The contentid will be used to refer to this attachment in
/// another mime part of the email.
/// </summary>
/// <param name="content">The contents of the file</param>
/// <param name="contentid">the content id value</param>
public FileAttachment(String content, String contentid)
{
if (this.ContentType==null)
{
this.ContentType="binary/octet-stream";
}
this.Contents=content;
this.CharSet=null;
this.Encoding=EncodingType.Base64;
this._contentid=contentid;
}
}
}
@@ -0,0 +1,279 @@
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using log4net;
namespace DotNetOpenMail
{
/// <summary>
/// Perform the low-level interaction with the external
/// SMTP server
/// </summary>
public class GenericSmtpNegotiator : TcpClient, ISmtpProxy
{
private bool _isConnected=false;
private static readonly ILog log = LogManager.GetLogger(typeof(GenericSmtpNegotiator));
private IPEndPoint _ipEndPoint;
private int _timeout=30000; // default is 30 seconds
/// <summary>
/// Create an instance of the GenericSmtpNegotiator
/// </summary>
/// <param name="ipEndPoint"></param>
public GenericSmtpNegotiator(IPEndPoint ipEndPoint)
{
this._ipEndPoint=ipEndPoint;
this.ReceiveTimeout=_timeout;
}
#region Open
/// <summary>
/// Connect to the server and return the initial
/// welcome string. Throw a MailException if we
/// can't connect.
/// </summary>
/// <returns></returns>
public SmtpResponse Open()
{
try {
Connect(_ipEndPoint);
}
catch (Exception ex)
{
throw new MailException("Could not connect to "+_ipEndPoint.Address+":"+_ipEndPoint.Port, ex);
}
_isConnected=true;
return ReadSmtpResponse();
}
#endregion
#region Helo
/// <summary>
/// Send the HELO string.
/// Throw a MailException if we can't connect.
/// </summary>
/// <returns>the SMTP response</returns>
public SmtpResponse Helo(String localHostName)
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
String message = "HELO "+localHostName+SmtpProxy.ENDOFLINE;
//LogDebug("SENDING: "+message);
Write(message);
return ReadSmtpResponse();
}
#endregion
#region MailFrom
/// <summary>
/// Send the MAIL FROM command
/// Throw a MailException if we can't connect.
/// </summary>
/// <param name="mailfrom">The Envelope-From address</param>
/// <returns>the SMTP response</returns>
public SmtpResponse MailFrom(EmailAddress mailfrom)
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
String message = "MAIL FROM: <"+mailfrom.Email+">"+SmtpProxy.ENDOFLINE;
LogDebug("SENDING: "+message);
Write(message);
return ReadSmtpResponse();
}
#endregion
#region RcptTo
/// <summary>
/// Send the MAIL FROM command
/// Throw a MailException if we can't connect.
/// </summary>
/// <param name="rcpttoaddress">A recipient's address</param>
/// <returns>the SMTP response</returns>
public SmtpResponse RcptTo(EmailAddress rcpttoaddress)
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
String message= "RCPT TO: <"+rcpttoaddress.Email+">"+SmtpProxy.ENDOFLINE;
LogDebug("SENDING: "+message);
Write(message);
return ReadSmtpResponse();
}
#endregion
#region Data
/// <summary>
/// Send the DATA string (without the data)
/// Throw a MailException if we can't connect.
/// </summary>
/// <returns>the SMTP response</returns>
public SmtpResponse Data()
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
String message = "DATA"+SmtpProxy.ENDOFLINE;
//LogDebug("SENDING: "+message);
Write(message);
return ReadSmtpResponse();
}
#endregion
#region WriteData
/// <summary>
/// Send the message content string
/// Throw a MailException if we can't
/// connect.
/// </summary>
/// <returns>the SMTP response</returns>
public SmtpResponse WriteData(String message)
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
StringReader reader=new StringReader(message);
String line=null;
while ((line=reader.ReadLine())!=null)
{
// checking for dot at the beginning of the
// line (RFC821 sec. 4.5.2)
if (line.Length > 0 && line[0]=='.')
{
Write("."+line+SmtpProxy.ENDOFLINE);
}
else
{
Write(line+SmtpProxy.ENDOFLINE);
}
}
Write(SmtpProxy.ENDOFLINE+"."+SmtpProxy.ENDOFLINE);
return ReadSmtpResponse();
}
#endregion
#region ReadSmtpResponse
private SmtpResponse ReadSmtpResponse()
{
String response=ReadResponse();
String responseCodeStr=response.Substring(0, 3);
String responseMessage="";
if (response.Length > 4)
{
responseMessage=response.Substring(4);
}
try
{
int responseCode=Convert.ToInt32(responseCodeStr);
return new SmtpResponse(responseCode, responseMessage);
}
catch
{
throw new MailException("Could not understand response from server: "+response);
}
}
#endregion
#region Write
/// <summary>
/// Write a string to the current connection.
/// </summary>
/// <param name="message"></param>
private void Write(string message)
{
try
{
System.Text.ASCIIEncoding en = new System.Text.ASCIIEncoding() ;
byte[] WriteBuffer = new byte[1024] ;
WriteBuffer = en.GetBytes(message) ;
NetworkStream stream = GetStream() ;
stream.Write(WriteBuffer,0,WriteBuffer.Length);
}
catch (Exception ex)
{
LogError(ex.Message);
throw new MailException("Error while sending data to the server: "+ex.Message, ex);
}
}
#endregion
#region Quit
/// <summary>
/// Send the QUIT command
/// Throw a MailException if we can't connect.
/// </summary>
/// <returns>the SMTP response</returns>
public SmtpResponse Quit()
{
if (!_isConnected)
{
throw new MailException("The connection is closed.");
}
Write("QUIT"+SmtpProxy.ENDOFLINE);
return ReadSmtpResponse();
}
#endregion
#region ReadResponse
private string ReadResponse()
{
try
{
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
byte []serverbuff = new Byte[1024];
NetworkStream stream = GetStream();
int count = stream.Read( serverbuff, 0, 1024 );
if (count == 0)
{
return "";
}
return enc.GetString( serverbuff, 0, count );
}
catch (Exception ex)
{
LogError(ex.Message);
throw new MailException("Error while receiving data from server: "+ex.Message, ex);
}
}
#endregion
#region LogError
private void LogError(String message)
{
log.Error(message);
}
#endregion
#region LogDebug
private void LogDebug(String message)
{
log.Debug(message);
}
#endregion
}
}
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using DotNetOpenMail.Encoding;
using DotNetOpenMail.Utils;
namespace DotNetOpenMail
{
/// <summary>
/// An HTML email attachment
/// </summary>
public class HtmlAttachment : AbstractEmailAttachment
{
/// <summary>
/// Create a new HTML Attachment. It flags the content/type
/// as "text/html", uses Quoted Printable encoding by
/// default, and uses the default character set, which is
/// ISO-8859-1 unless otherwise specified in the .config file.
/// </summary>
/// <param name="contents">The HTML content of the attachment</param>
public HtmlAttachment(String contents)
{
this.ContentType="text/html";
this.Contents=contents;
this.CharSet=System.Text.Encoding.GetEncoding(Configuration.GetInstance().GetDefaultEncoding("iso-8859-1"));
this.Encoding=EncodingType.QuotedPrintable;
}
}
}
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail
{
/// <summary>
/// Objects of a class which implements this interface
/// can be converted to a string which can be used in
/// an email.
/// </summary>
internal interface IEmailStringable
{
String ToDataString();
}
}
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2005 Mike Bridge <mike@bridgecanada.com>
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace DotNetOpenMail
{
/// <summary>
/// A message which can be sent.
/// </summary>
internal interface ISendableMessage : IEmailStringable
{
bool Send(SmtpServer smtpserver);
}
}

Some files were not shown because too many files have changed in this diff Show More