Step by Step

Friday, May 13, 2011

How to send mail using Asp.net



Default to send mail
using System.Net.Mail;




MailMessage email = new MailMessage();


email.Subject = "My first test email";
email.SubjectEncoding = System.Text.Encoding.UTF8;
email.Body = body;
email.BodyEncoding = System.Text.Encoding.UTF8;
email.To.Add(new MailAddress("recipient@domain.com"));
email.Sender = new MailAddress("sender@domain.com");
email.From = new MailAddress("sender@domain.com");
email.Attachments.Add(new Attachment("c:\\my-attachment.pdf"));


try {
SmtpClient client = new SmtpClient("mail.my-domain.com", 25);
// 25 is the default SMTP port
client.Send(email);
} catch (SmtpException ex) {
...
}


Email Address Validation
Another common problem - validating email address input - can be handled easilly in ASP .NET
Validation is important. It reduces the amount of incorrect or fabricated email addresses clogging up your database.
At a very minimum, the format of the address should be tested, and this is typically accomplished using regular expressions.
using System.Text.RegularExpressions;


...


private bool EmailAddressIsValid(string email) {
string regExPattern = @"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +
@"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
@".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
Regex regEx = new Regex(regExPattern);
return regEx.IsMatch(email);
}
Note that this can be tested client-side using Javascript as well.
Socket to 'em
But let's say you want to be extra sure that bogus addresses will not violate your precious database space.
There are two other aspects you can test, and here ASP .NET comes into its own, using its socket functionality.
(SMTP emails are sent using socket connections. In fact you can write your own version of the SmtpClient class using sockets. But why re-invent the wheel? Unless you're really bored. Or drunk. Or both.)
Domain validation


First, test whether the email domain (the part after the @) exists.
All you have to do is open a socket connection with the domain, and see what happens.
using System.Net;
using System.Net.Sockets;


string email = "recipient@some-domain.com";
string[] host = email.Split('@');
string hostName = host[1];
Socket socket;
try {
IPHostEntry entry = Dns.GetHostEntry(hostName);
IPEndPoint endPoint = new IPEndPoint(entry.AddressList[0], 25);
socket = new Socket(endPoint.AddressFamily, SocketType.Stream,
ProtocolType.Tcp);
socket.Connect(endPoint);
//Yippee - the email domain exists!
} catch (SocketException se) {
//Oops - the email domain is not valid!
}


Account validation


Even if the domain exists and is willing to receive mail, we still don't know whether the mail account exists for the domain. The only way to be sure of this is to try to connect to the account.
We continue with the socket communication process that we started in the previous stage (domain validation). This is the very process used to send an email, and we stop only very short of sending email content. This requires a series of interactions with the email server. We use utility functions to help us: SendData and

CheckSmtpResponse

if (!CheckSmtpResponse(SmtpResponse.CONNECT_SUCCESS)) { //account is invalid! }


//test HELO server
SendData(string.Format("HELO {0}\r\n", Dns.GetHostName()));
if (!CheckSmtpResponse(SmtpResponse.GENERIC_SUCCESS)) { //account is invalid! }


//test for sender domain on blacklist
SendData(string.Format("MAIL From: {0}\r\n", _SenderEmail));
if (!CheckSmtpResponse(SmtpResponse.GENERIC_SUCCESS)) { //account is invalid! }


//test send
SendData(string.Format("RCPT TO: {0}\r\n", email));
if (!CheckSmtpResponse(SmtpResponse.GENERIC_SUCCESS)) { //account is invalid! }


//account is valid!


//utility funtions:


void SendData(string message) {
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(message);
socket.Send(bytes, 0, bytes.Length, SocketFlags.None);
}


enum SmtpResponse : int {
CONNECT_SUCCESS = 220,
GENERIC_SUCCESS = 250,
DATA_SUCCESS = 354,
QUIT_SUCCESS = 221
}


bool CheckSmtpResponse(SmtpResponse code) {
string responseString;
int responseCode;
byte[] bytes = new byte[1024];
while (socket.Available == 0) {
System.Threading.Thread.Sleep(100);
}
socket.Receive(bytes, socket.Available, SocketFlags.None);
responseString = System.Text.Encoding.ASCII.GetString(bytes);
responseCode = Convert.ToInt32(responseString.Substring(0, 3));
return responseCode.Equals(Convert.ToInt32(code));
}

Tuesday, May 10, 2011

Var Vis Dynamic in C# 4


C# 3.0 introduced the implicit type "var". I've explained var as saying:
"I'm too lazy to tell you the type of this variable, so you figure it out, compiler."
However, it's more useful than just promoting terseness or laziness:
1
2
var i = 10; // implicitly typed
int i = 10; //explicitly typed
Although var is a great way to start arguments about coding standards at your work, there are times when it is required around anonymous types. Here's an example from MSDN:
1
2
3
4
5
6
7
8
9
10
11
12
/ Example: var is required because
// the select clause specifies an anonymous type
var custQuery = from cust in customers
                where cust.City == "Phoenix"
                select new { cust.Name, cust.Phone };
// var must be used because each item
// in the sequence is an anonymous type
foreach (var item in custQuery)
{
    Console.WriteLine("Name={0}, Phone={1}", item.Name, item.Phone);
}
C# 4 (not 4.0, the marketing folks say it's .NET 4, etc.) adds the dynamic keyword. I've explained this saying:
"There's no way for you or I to know the type of this now, compiler, so let's hope that the runtime figures it out."
Here's how this looks from an Intellisense point of view. Here I'm hovering over the dynamic keyword:
dynamiccalc1
And here is the tooltip after pressing "." after "calc."
dynamiccalc2
Now, to the interesting question of the day. Christoff Turner asked this question, essentially:
"I noticed the following while doing some research within C# 4.0:"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
namespace ConsoleApplication1
{
  class Program
  {
      static void f(Int32 x) { }
      static void f(dynamic x) {}
      static void f(Int32 x, dynamic y) {}
      static void f(dynamic x, Int32 y) {}
      static void f(Int32 x, dynamic y, Int32 z) {}
      static void f(dynamic x, Int32 y, dynamic z) {}
      static void Main(string[] args)
      {
          f(10); // Works - obvious
          f(10, 10); // Ambiguous - obvious
          f(10, 10, 10); // Ambiguous - not so obvious - since it should be possible to resolve
      }
  }
}
"Looking at f(10,10,10), what is the reasoning behind this call being ambiguous?"
I stared it it a while longer, then realized what is happening, and called Mads Torgersen to confirm. Mads says this.
In short, the behavior is totally by design:
  • dynamic in method signatures doesn’t come into it: it behaves like System.Object does.
  • Given that, neither of the ternary signatures is better because each fits better than the other on some arguments (Int32 fits 10 better than object does)
The key point here, in bold, because it's significant is: having the type dynamic means “use my runtime type for binding”.
The problem in the context of method calls is that you can't use the runtime type of something until, um, runtime. ;) Binding with dynamic expressions (dynamic binding) happens at runtime.  In this case, we're compiling against method signatures that are known at compile type and we're compiling with a (mostly) static language, so there's no dynamic method dispatching happening that could select a different method overload at runtime.
The dynamic type is statically-typed as dynamic. The compile-time type is "dynamic" (but really it's object, hence the method overloading trouble.)
Another way to look at this is with Reflector. This C# code:
1
static void f(Int32 x, dynamic y, Int32 z) {}
is essentially this, from a method signature point of view:
1
static void f(int x, [Dynamic] object y, int z) {}
and if there was a method that returned dynamic, it'd look like this:
1
2
[return: Dynamic]
private static object GetCalculator() {}
So, given how dynamic works as a type, how the DLR works in the context of method dispatching, etc, you can see why things didn't work like Christoff thought they would.