Posts Tagged ‘SMTP’

Send encrypted email using S/MIME

Wednesday, January 26th, 2011

Sending encrypted and signed S/MIME messages has never been easier:

// C# version

IMail email = Mail
    .Html("<html><body>Encrypted and signed</body></html>")
    .Subject("Encrypted and signed")
    .From(new MailBox("email@in-the-certificate.com", "Alice"))
    .To(new MailBox("bob@mail.com", "Bob"))
    .AddAttachment(@"c:\report_2010.pdf")
    .SignWith(new X509Certificate2("SignCertificate.pfx", ""))
    .EncryptWith(new X509Certificate2("EncryptCertificate.pfx", ""))
    .EncryptWith(new X509Certificate2("BobsCertificate.pfx", ""))
    .Create();

using (Smtp client = new Smtp())
{
    client.Connect("smtp.example.com"); // or ConnectSSL
    client.UseBestLogin("user", "password");
    client.SendMessage(email);
    client.Close();
}
' VB.NET version

Dim email As IMail = Mail _
	.Html("<html><body>Encrypted and signed</body></html>") _
	.Subject("Encrypted and signed") _
	.From(New MailBox("email@in-the-certificate.com", "Alice")) _
	.To(New MailBox("bob@mail.com", "Bob")) _
	.AddAttachment("c:\report_2010.pdf") _
	.SignWith(New X509Certificate2("SignCertificate.pfx", "")) _
	.EncryptWith(New X509Certificate2("EncryptCertificate.pfx", "")) _
	.EncryptWith(New X509Certificate2("BobsCertificate.pfx", "")) _
	.Create()

Using client As New Smtp()
	client.Connect("smtp.example.com") ' or ConnectSSL
	client.UseBestLogin("user", "password")
	client.SendMessage(email)
	client.Close()
End Using

Remember to encrypt your emails with both sender’s and receiver’s certificates.
This way both parties are able to decrypt such emails.

Common errors you may encounter:

  • Please use the PersistKeySet flag when loading from file (new X509Certificate2(_certificatePath, “”, X509KeyStorageFlags.PersistKeySet);) and adding to store
  • “Bad key” exception message means that certificate was not for key exchange – makecert needs an extra parameter to create certificate that can be used for symmetric algorithm key exchange: -sky exchange.
  • “the enveloped data-message does not contain the specified recipient” means that certificate with the private key is not deployed into the current account/local machine personal store, or not in the certificates list

You can use following commands in VisualStudio Command Prompt to create test certificate:

makecert.exe -pe -r -sv Test_Keys.pvk -n "CN=John Doe,E=email@in-the-certificate.com" -sky exchange Test.cer

pvk2pfx.exe -pvk Test_Keys.pvk -spc Test.cer -pfx Test.pfx

I have problems issuing IMAP, POP3 or SMTP command

Wednesday, January 5th, 2011

Mail.dll is a rock solid product, however most email servers don’t follow rigorously the RFC specifications. In the following few steps we’ll help you gather the information we need to make Mail.dll clients better.

If you have problems parsing a message please go here.

1.
First please check if you have the latest version installed.

2.
Please identify the command/set of commands that cause problems.

3.
Enable logging for Mail.dll clients:

// C# version:

Log.Enabled = true;
' VB.NET version:

Log.Enabled = True

You can observe standard Visual Studio trace output or add a custom listener to Trace.Listeners collection.

You can also enable logging using App.config file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.diagnostics>
      <switches>
        <add name="Mail.dll" value="True" />
      </switches>
    </system.diagnostics>
</configuration>

You can create your custom TraceListener that writes log to file:

// C# version:

internal class MyListener : TextWriterTraceListener
{
    public MyListener(string fileName)
        : base(fileName)
    {
    }

    public override void Write(string message, string category)
    {
        if (category == "Mail.dll")
            base.Write(message, category);
    }

    public override void WriteLine(string message, string category)
    {
        if (category == "Mail.dll")
            base.WriteLine(message, category);
    }
}
' VB.NET version

Friend Class MyListener
	Inherits TextWriterTraceListener
	Public Sub New(fileName As String)
		MyBase.New(fileName)
	End Sub

	Public Overrides Sub Write(message As String, category As String)
		If category = "Mail.dll" Then
			MyBase.Write(message, category)
		End If
	End Sub

	Public Overrides Sub WriteLine(message As String, category As String)
		If category = "Mail.dll" Then
			MyBase.WriteLine(message, category)
		End If
	End Sub
End Class

…then add it to Listeners collection:

// C# version:

Log.Enabled = true;
Trace.Listeners.Add(new MyListener(@"c:mail_log.txt"));
Trace.AutoFlush = true;
' VB.NET version:

Log.Enabled = True
Trace.Listeners.Add(New MyListener("c:mail_log.txt"))
Trace.AutoFlush = True

4.
Perform the operations that cause the problems, and save the log to file.
You can remove username and password, but please do not modify the file extensively. If you do, it may be impossible to reproduce the issue.
In particular do not change new line format nor encoding.

5.
Please answer following questions:

  • What exception are you getting?
  • What is the exception stack trace?
  • What is the exception message?
  • What result you expect?
  • What result are you getting?
  • Which .NET Framework version are you using?
  • Is it console, windows forms, windows service or web application?
  • If it is possible please attach the source code you are using

6.
Finally please zip the log file and send it as attachment, along with all the answers to .

Thanks!

I have problems parsing the message

Tuesday, January 4th, 2011

Mail.dll is a rock solid product, however most of the emails don’t follow rigorously the RFC specifications. In the following few steps we’ll help you gather the information we need to make Mail.dll parser better.

If you have problems issuing IMAP, POP3, or SMTP command please go here.

1.
First please check if you have the latest version installed.

2.
Please identify unique id (UID) of the message you are having problems with.

3.
Next step is to download entire message and save it as raw eml file.
Note that you should not parse the email, so there is no need to use MailBuilder and IMail classes.

IMAP version:

// C# code

long uid = 12345;

using (Imap imap = new Imap())
{
    imap.Connect("server");
    // imap.ConnectSSL("server"); // if you need SSL connection.
    imap.UseBestLogin("user", "password");
    imap.SelectInbox();

    string eml = imap.GetMessageByUID(uid);
    string fileName = string.Format(@"c:\email_{0}.eml", uid);
    File.WriteAllText(fileName, eml, Encoding.UTF8);

    imap.Close();
}
' VB.NET code

Dim uid As Long = 12345

Using imap As New Imap()
	imap.Connect("server")
	' imap.ConnectSSL("server") ' if you need SSL connection.
	imap.UseBestLogin("user", "password")
	imap.SelectInbox()

	Dim eml As String = imap.GetMessageByUID(uid)
	Dim fileName As String = String.Format("c:\email_{0}.eml", uid)
	File.WriteAllText(fileName, eml, Encoding.UTF8)

	imap.Close()
End Using

POP3 version:

// C# code

string uid = "12345";

using (Pop3 pop3 = new Pop3())
{
    pop3.Connect("server");
    // pop3.ConnectSSL("server"); // if you need SSL connection.
    pop3.Login("user", "password");

    string eml = pop3.GetMessageByUID(uid));
    string fileName = string.Format(@"c:\email_{0}.eml", uid);
    File.WriteAllText(fileName, eml, Encoding.UTF8);

    pop3.Close();
}
' VB.NET code

Dim uid As String = "12345"

Using pop3 As New Pop3()
	pop3.Connect("server")
	' pop3.ConnectSSL("server"); ' if you need SSL connection.
	pop3.Login("user", "password")

	Dim eml As String = pop3.GetMessageByUID(uid)
	Dim fileName As String = String.Format("c:\email_{0}.eml", uid)
	File.WriteAllText(fileName, eml, Encoding.UTF8)

	pop3.Close()
End Using

4.
Please answer following questions:

  • What exception are you getting?
  • What is the exception stack trace?
  • What is the exception message?
  • What result you expect?
  • What result are you getting?
  • Which .NET Framework version are you using?
  • Is it console, windows forms, windows service or web application?
  • If it is possible please attach the source code you are using

5.
Finally please zip the eml file and send it as attachment, along with all the answers to
.

Thanks!

Send iCalendar recurring meeting requests

Friday, November 19th, 2010

First add all necessary namespaces:

// C# version

using System;
using Limilabs.Mail;
using Limilabs.Mail.Appointments;
using Limilabs.Mail.Headers;
using Fluent = Limilabs.Mail.Fluent;
using Limilabs.Client.SMTP;
' VB.NET version

Imports System;
Imports Limilabs.Mail;
Imports Limilabs.Mail.Appointments;
Imports Limilabs.Mail.Headers;
Imports Fluent = Limilabs.Mail.Fluent;
Imports Limilabs.Client.SMTP;

Now, we’ll create an appointment, specify it’s recurring options and send it:

// C# version

Appointment appointment = new Appointment();
Event newEvent = appointment.AddEvent();
newEvent.SetOrganizer(new Person("Alice", "alice@example.org"));
newEvent.AddParticipant(new Participant("Bob", "bob@gmail.com"));
newEvent.Description = "We need to talk about the daily report";
newEvent.Summary = "Daily report meeting";
newEvent.Start = new DateTime(2010, 11, 29, 16, 0, 0);
newEvent.End = new DateTime(2010, 11, 29, 17, 0, 0);
newEvent.Priority = 5;
newEvent.Class = EventClass.Public;

RecurringRule rule = newEvent.AddRecurringRule();
rule.Interval = 1;
rule.Until = new DateTime(2011, 12, 1); // -or- rule.Count = 10;

// Every week on  Mon, Tue, Wed, Thu Fri:
rule.Frequency = Frequency.Weekly;
rule.ByDay.AddRange(new[] {
    Weekday.Monday,
    Weekday.Tuesday,
    Weekday.Wednesday,
    Weekday.Thursday,
    Weekday.Friday });

Alarm alarm = newEvent.AddAlarm();
alarm.Description = "Reminder";
alarm.BeforeStart(TimeSpan.FromMinutes(5));

IMail email = Fluent.Mail.Text("Daily report meeting at 4PM")
    .Subject("Daily report meeting")
    .From(new MailBox("alice@example.org", "Alice"))
    .To(new MailBox("bob@example.org", "Bob"))
    .AddAppointment(appointment)
    .Create();

using (Smtp client = new Smtp())
{
    client.ConnectSSL("smtp.example.org");
    client.UseBestLogin("user", "password");
    client.SendMessage(email);
    client.Close();
}
' VB.NET version

Dim appointment As New Appointment()
Dim newEvent As [Event] = appointment.AddEvent()
newEvent.SetOrganizer(New Person("Alice", "alice@example.org"))
newEvent.AddParticipant(New Participant("Bob", "bob@gmail.com"))
newEvent.Description = "We need to talk about the daily report"
newEvent.Summary = "Daily report meeting"
newEvent.Start = New DateTime(2010, 11, 29, 16, 0, 0)
newEvent.[End] = New DateTime(2010, 11, 29, 17, 0, 0)
newEvent.Priority = 5
newEvent.[Class] = EventClass.[Public]

Dim rule As RecurringRule = newEvent.AddRecurringRule()
rule.Interval = 1
rule.Until = New DateTime(2011, 12, 1)
' -or- rule.Count = 10;
' Every week on  Mon, Tue, Wed, Thu Fri:
rule.Frequency = Frequency.Weekly
rule.ByDay.AddRange(New Weekday() {Weekday.Monday _
                                   , Weekday.Tuesday _
                                   , Weekday.Wednesday _
                                   , Weekday.Thursday _
                                   , Weekday.Friday})

Dim alarm As Alarm = newEvent.AddAlarm()
alarm.Description = "Reminder"
alarm.BeforeStart(TimeSpan.FromMinutes(5))

Dim email As IMail = Fluent.Mail.Text("Daily report meeting at 4PM") _
    .Subject("Daily report meeting") _
    .From(New MailBox("alice@example.org", "Alice")) _
    .[To](New MailBox("bob@example.org", "Bob")) _
    .AddAppointment(appointment).Create()

Using client As New Smtp()
    client.ConnectSSL("smtp.example.org")
    client.UseBestLogin("user", "password")
    client.SendMessage(email)
    client.Close()
End Using

This is how it looks like in Gmail:

Recurring appointment

Recurring appointment

Here are the few samples of how you can set the frequency:

Daily:

// C# version

rule.Frequency = Frequency.Daily;
' VB.NET version

rule.Frequency = Frequency.Daily

Every month on last monday:

// C# version

rule.Frequency = Frequency.Monthly;
rule.ByDay.Add(Weekday.LastMonday);
' VB.NET version

rule.Frequency = Frequency.Monthly
rule.ByDay.Add(Weekday.LastMonday)

Every month on second but last monday:

// C# version

rule.Frequency = Frequency.Monthly;
rule.ByDay.Add(new Weekday(-2, Weekday.Monday));
' VB.NET version

rule.Frequency = Frequency.Monthly
rule.ByDay.Add(New Weekday(-2, Weekday.Monday))

A connection attempt failed

Monday, November 15th, 2010

If you are getting following or similar exception:
“A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond” or “No connection could be made because the target machine actively refused it.” most likely you provided incorrect server, port, and SSL usage configuration to Connect, or ConnectSSL methods.

Most email providers (like Gmail, Hotmail, Yahoo and others) use default ports. Connect() and ConnectSSL() and fluent interface use those ports when not specified otherwise.

Default ports for email protocols are:

Protocol Without SSL With SSL
IMAP 143 993
POP3 110 995
SMTP 25 465

Please ask your email server administrator for server, port, and SSL usage,
if those are not standard there is no way you can guess them.

Please also make sure that:

  • you are using correct client class with protocol and port you plan to use (Pop3 class with POP3 protocol, Imap class with IMAP, and Smtp class with SMTP protocol)
  • you are using ConnectSSL when you require SSL, and Connect when you don’t
  • firewall and antivirus software are disabled or configured correctly
  • the protocol you are trying to use is enabled on the server. Exchange or Gmail can have some protocols disabled by default

Following articles can help you with that:

Establishing connection using default port is simple:

// C#

client.Connect("mail.example.com");
' VB.NET

client.Connect("mail.example.com")

or if SSL is enabled:

// C#

client.ConnectSSL("mail.example.com");
' VB.NET

client.ConnectSSL("mail.example.com")

If you need to specify different port just use overloaded version of Connect method:

// C#

client.Connect("mail.example.com", 999);
' VB.NET

client.Connect("mail.example.com", 999)

If you are using SSL:

// C#

client.ConnectSSL("mail.example.com", 999);
' VB.NET

client.ConnectSSL("mail.example.com", 999)

If you need to specify different port using fluent interface use OnPort() method:

// C# version

Mail.Text(@"Hello")
  .To("to@mail.com")
  .From("from@mail.com")
  .Subject("Subject")
  .UsingNewSmtp()
  .Server(_server)
  .WithSSL()
  .OnPort(443)
  .WithCredentials("user", "password")
  .Send();

Some servers require explicit SSL (Usually this triggers “The handshake failed due to an unexpected packet format” exception) please look at following articles for details:

If you have problems with SSL, your server may be using self-signed certificates:

Again when in doubt please ask your email server administrator for server, port, and SSL usage.