2 // System.Web.Mail.SmtpClient.cs
5 // Per Arneng <pt99par@student.bth.se>
6 // Sanjay Gupta <gsanjay@novell.com>
7 // (C) 2004, Novell, Inc. (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Collections;
35 using System.Net.Sockets;
36 using System.Security.Permissions;
38 namespace System.Web.Mail {
40 #pragma warning disable 618
43 /// represents a conntection to a smtp server
44 internal class SmtpClient {
46 private string server;
47 private TcpClient tcpConnection;
48 private SmtpStream smtp;
50 //Initialise the variables and connect
51 public SmtpClient( string server ) {
57 // make the actual connection
58 // and HELO handshaking
59 private void Connect() {
60 tcpConnection = new TcpClient( server , 25 );
62 Stream stream = tcpConnection.GetStream();
63 smtp = new SmtpStream( stream );
65 // read the server greeting
67 smtp.CheckForStatusCode( 220 );
69 // write the HELO command to the server
70 smtp.WriteHelo( Dns.GetHostName() );
74 public void Send( MailMessageWrapper msg ) {
76 if( msg.From == null ) {
77 throw new SmtpException( "From property must be set." );
80 if( msg.To == null ) {
81 if( msg.To.Count < 1 ) throw new SmtpException( "Atleast one recipient must be set." );
85 // start with a reset incase old data
86 // is present at the server in this session
89 // write the mail from command
90 smtp.WriteMailFrom( msg.From.Address );
92 // write the rcpt to command for the To addresses
93 foreach( MailAddress addr in msg.To ) {
94 smtp.WriteRcptTo( addr.Address );
97 // write the rcpt to command for the Cc addresses
98 foreach( MailAddress addr in msg.Cc ) {
99 smtp.WriteRcptTo( addr.Address );
102 // write the rcpt to command for the Bcc addresses
103 foreach( MailAddress addr in msg.Bcc ) {
104 smtp.WriteRcptTo( addr.Address );
107 // write the data command and then
111 if( msg.Attachments.Count == 0 ) {
112 SendSinglepartMail( msg );
115 SendMultipartMail( msg );
119 // write the data end tag "."
120 smtp.WriteDataEndTag();
124 // sends a single part mail to the server
125 private void SendSinglepartMail( MailMessageWrapper msg ) {
128 smtp.WriteHeader( msg.Header );
130 // send the mail body
131 smtp.WriteBytes( msg.BodyEncoding.GetBytes( msg.Body ) );
135 // SECURITY-FIXME: lower assertion with imperative asserts
136 [FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
137 // sends a multipart mail to the server
138 private void SendMultipartMail( MailMessageWrapper msg ) {
140 // generate the boundary between attachments
141 string boundary = MailUtil.GenerateBoundary();
143 // set the Content-Type header to multipart/mixed
144 string bodyContentType = msg.Header.ContentType;
146 msg.Header.ContentType =
147 String.Format( "multipart/mixed;\r\n boundary={0}" , boundary );
150 smtp.WriteHeader( msg.Header );
152 // write the first part text part
153 // before the attachments
154 smtp.WriteBoundary( boundary );
156 MailHeader partHeader = new MailHeader();
157 partHeader.ContentType = bodyContentType;
160 // Add all the custom headers to body part as specified in
161 //Fields property of MailMessageWrapper
163 //Remove fields specific for authenticating to SMTP server.
164 //Need to incorporate AUTH command in SmtpStream to handle
165 //Authorization info. Its a temporary fix for Bug no 68829.
166 //Will dig some more on SMTP AUTH command, and then implement
167 //Authorization. - Sanjay
169 if (msg.Fields.Data ["http://schemas.microsoft.com/cdo/configuration/smtpauthenticate"] != null)
170 msg.Fields.Data.Remove ("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate");
171 if (msg.Fields.Data ["http://schemas.microsoft.com/cdo/configuration/sendusername"] != null)
172 msg.Fields.Data.Remove ("http://schemas.microsoft.com/cdo/configuration/sendusername");
\r
173 if (msg.Fields.Data ["http://schemas.microsoft.com/cdo/configuration/sendpassword"] != null)
\r
174 msg.Fields.Data.Remove ("http://schemas.microsoft.com/cdo/configuration/sendpassword");
175 partHeader.Data.Add (msg.Fields.Data);
178 smtp.WriteHeader( partHeader );
180 // FIXME: probably need to use QP or Base64 on everything higher
181 // then 8-bit .. like utf-16
182 smtp.WriteBytes( msg.BodyEncoding.GetBytes( msg.Body ) );
184 smtp.WriteBoundary( boundary );
186 // now start to write the attachments
188 for( int i=0; i< msg.Attachments.Count ; i++ ) {
189 MailAttachment a = (MailAttachment)msg.Attachments[ i ];
191 FileInfo fileInfo = new FileInfo( a.Filename );
193 MailHeader aHeader = new MailHeader();
195 aHeader.ContentType =
196 String.Format (MimeTypes.GetMimeType (fileInfo.Name) + "; name=\"{0}\"",fileInfo.Name);
198 aHeader.ContentDisposition =
199 String.Format( "attachment; filename=\"{0}\"" , fileInfo.Name );
201 aHeader.ContentTransferEncoding = a.Encoding.ToString();
203 smtp.WriteHeader( aHeader );
205 // perform the actual writing of the file.
206 // read from the file stream and write to the tcp stream
207 FileStream ins = fileInfo.OpenRead ();
209 // create an apropriate encoder
210 IAttachmentEncoder encoder;
211 if( a.Encoding == MailEncoding.UUEncode ) {
212 encoder = new UUAttachmentEncoder( 644 , fileInfo.Name );
214 encoder = new Base64AttachmentEncoder();
217 encoder.EncodeStream( ins , smtp.Stream );
222 smtp.WriteLine( "" );
224 // if it is the last attachment write
225 // the final boundary otherwise write
227 if( i < (msg.Attachments.Count - 1) ) {
228 smtp.WriteBoundary( boundary );
230 smtp.WriteFinalBoundary( boundary );
237 // send quit command and
238 // closes the connection
239 public void Close() {
242 tcpConnection.Close();
249 #pragma warning restore 618