2009-01-23

Sending email in C# - Maybe there *is* a way

Almost a year ago, I was bemoaning the fact that sending email is hard. Well, recently, my client went from a PC to a Mac, and he needed some help installing the program in the virtual XP session. When I was there, I set up the Outlook Express client so that the PDF statements could be emailed out from the virtual XP world. I figured that, since I know his email client, perhaps I could find something specific to that client for sending email.

Googling around for sending email from C# with Outlook Express, I eventually came across this CodeProject article: Programmatically adding attachments to emails in C# and VB.NET. I took the code and dropped it into my project pretty much as-is. My development machine is now a Windows Vista laptop, but this code worked just fine, starting up a Windows Live Mail window with the file attached.

There were a couple issues. One, if Live Mail wasn't started first, then I'd get an error from the MAPI call — apparently the client needs to be initialized before the call is made. (The MAPI call was starting Live Mail, but Live Mail did not appear to be in a ready state then the email was sent to it.) The second is that the SendMailPopup call (which is the one I want) blocks until the email message is closed (i.e. sent or discarded). The comments in that article, however, mention a method to split that call onto another thread, so I should be able to prepare and open several emails at once.

So I think I will create a configuration parameter that will allow the toggling of attempting to use MAPI. It should work, but it'll be preferable to have something to fall back on.

Incidentally, a discussion thread over at Channel 9 pretty much summed up the problem as such:

  • If you have Outlook, you can do it. (Use Outlook automation)
  • If you have a MAPI profile (e.g. Outlook Express), you can do it.
  • If you have SMTP, you can do it. (System.Web.Mail standard)

To which I'll add:

  • If you don't know what you have, you can try it. (mailto: link, attachments not supported)

Just for kicks, I tried this on my PC at work, which is running XP and has the Mozilla Thunderbird email client installed. It worked beautifully, whether I had Thunderbird running before I called SendMailPopup or not. I don't know if Outlook would also respond to this code or not. (I'll have to try the compiled program on my desktop with Outlook when I'm done.) If so, it could simplify things, as much as they can be considered "simplified" in what seems to be a complicated situation.

At least I'm in the fortunate situation that I'm writing this for a known, single client and a known configuration.

I do wonder why there's not a managed MAPI wrapper though. For my own convenience, I'm gathering emails into a collection of System.Web.Mail.MailMessage objects before I try sending them. Why is there no System.Web.Mail.Mapi.Send method? Maybe a System.Web.Mail.Mapi.IsClientRunning method, and so on.

2009-01-20

The Civility Project

My wife sent me a link to an article about two people with very different political, religious, and ideological views ended up forming a correspondence when one recognized and commended the other for acting courteously towards those who disagreed with him on several television appearances.

The two got together and realized that there is so much anger and divisiveness in America today, particularly about politics and religion. People talk and debate not to share ideas and encourage discussion, but to attack, divide, and belittle convictions and beliefs they don't agree with.

To that end, they came up with The Civility Project, a web site that encourages people to be civil by taking "The Civility Pledge":

  • I will be civil in my public discourse and behavior.
  • I will be respectful of others whether or not I agree with them.
  • I will stand against incivility when I see it.

The site also encourages people to post examples of civility and incivility reported in the media, and to comment on it — an open invitation to civil discourse.

It's a fairly new site, with not a lot of content as of yet, but I do hope it gets more attention. Wouldn't it be nice if people could just talk and listen, instead of berate and attack?

2009-01-12

I know you are listening

Either someone on the Aurora City Council is reading this blog, or it just so happens that that someone else had a similar complaint and was already in the process of changing something I blogged about earlier.

In this post, I suggest that the very large "Speed Limit 40" sign before the end of the school zone is very misleading. It's been this way since I've traveled this road, at least a couple years. And yet, I noticed when I took my kids to school as the school year started up again for 2009 that the very large "Speed Limit 40" sign has been removed, and now a much more normal-sized sign — one of equal size as the "End School Zone" sign — is posted instead, on the same post as the "End School Zone" sign.

Coincidence? Maybe I should test this theory.

You know, I find it annoying that large piles of generic cash don't randomly show up on my doorstep.…

2009-01-09

Bandwidth for December

I almost forgot to check my bandwidth for December — and it shows. Unfortunately, vnstat only keeps the daily stats for the last 30 days, so the daily stats for the beginning of December are lost:

 

However, the total stats for the month are stored: 20,391MB down, 6,449MB up, 26,841MB total. I'm not sure what accounts for the spike in activity on the 30th, but the 31st may have been caused by us watching the Times Square festivities on the internet (which for some reason had a lesser effect than whatever happened the day before).

Worthy of note this month is that I've started watching the online web series The Guild in high-definition on Xbox Live. Although HD, they are short, less than 10 minutes each, so the file size each is only a couple hundred Megabytes apiece, about once a week.

Totals are down about 700MB from last month, with December showing the lowest usage since I started monitoring.

2009-01-07

DTC and Windows Firewall - A Rant

Let me preface this by saying: If you're looking for a solution to getting Microsoft Distributed Transaction Coordinator (MSDTC) working through Windows Firewall, this is not the post you're looking for. No solution exists here.

I'm working on a project that is in three parts — a rich Windows Forms client, a Web Service business and data access layer, and a SQL Server database. The QA guy was having an issue where some web service calls were timing out, causing the application to crash. While I couldn't replicate it, I did notice that the web service calls being made resulted in a spike of read locks on the database. I figured a viable option would be to have that service set a transaction scope with an isolation level of Read Uncommitted. It was a quick and dirty way to get it to read data without locking in a condition where, for whatever reason, it seemed that read locks were colliding. (Doesn't make a lot of sense to me, as nothing was writing to the database at the time, but it's all I had to go on.)

After trying and failing to use the Enterprise Library to create a transaction (it kept insisting the transaction and the command objects belonged to different connections, even when I created them equal), I decided to go with the System.Transactions namespace to manage it. From a code perspective, it would be much, much cleaner anyway.

It did perform much faster, without the spike in database locks, but it revealed another problem. In trying to solve the problem himself, QA guy thought he should try splitting the application up instead of running everything on one machine, so he put the database in a virtual PC. When he got the new web service code, it threw an error about being unable to connect to the DTC service on the database server.

This was a fortunate discovery, as it would've been a problem if we got to a client's environment and found this issue.

I created three VPCs of my own and put the three pieces each on its own VPC. The rest of the next two days, I spent trying to get DTC to work between the web service and the database server.

Everything ran fine when the Windows Firewall was disabled on all machines. First, DTC had to be configured on both the web service server and the database machines by enabling "Network DTC Access" and inbound and outbound "Transaction Manager Communication". Also, the DTC service on the SQL Server had to be started and set to Automatic start. (The web service server would start its own as needed.) Also, since my VPCs were in a workgroup and not a domain, I had to set DTC to use "No Authentication" rather than "Mutual". Quite a bit of extra work, but so far, not completely outside the realm of what we might possibly have to ask a client to do to their own servers.

Turning on the firewall on the client wasn't an issue. Turning on the firewall on the web service server caused an issue with both the servicing of web service requests and database access. The former was relieved by allowing port 80 through, naturally. The latter was relieved by creating an exception for the process C:\Windows\System32\MSDTC.exe, which was recommended by articles I found describing DTC and Windows Firewall (namely, that all machines participating in distributed transactions should have this exception).

Then there was the firewall on the database server. I had to allow port 1433 for SQL Server access. No problem. Doing that meant non-transactional methods worked without a hitch. But from there, for the life of me, I couldn't get DTC to go through. I tried allowing port 135. I tried adding MSDTC.exe as an exception. Nothing. It just wouldn't work.

One or two sites suggested opening up a range of ports that DCOM uses. However, since port ranges are not a valid exception for Win32's firewall, I did not feel adding a series of exceptions for each individual port from 5000 to 5020 was a viable option — not for me, and certainly not for our clients. Not all articles indicated this was necessary anyway.

It just. Wouldn't. Work.

Incidentally, the utility DTCPing apparently works fine (once you enable RPC on both machines through the Group Policy Editor, which I had to do since my VPCs are running XP Pro). This would seem to indicate that it's not a networking issue or even a firewall issue, just a DTC-refusing-to-work issue.

A lot of things bug me about this. For one, setting up DTC requires a lot of extra steps (turn on network access, mess with authentication, start service and set startup option on database server, create firewall exceptions) that can't (easily) be done in an install routine. Two, the fact that DTC was even used at all — the code in question created a TransactionScope object, created a DbCommand, and called LoadDataSet on a Database, before disposing of everything (except the DataSet). This, to me, should not be taking more than one connection to the same database, and therefore it should not require a distributed transaction coordinator at all. And of course the typical "this (apparently) fundamental piece of Windows systems is broken thanks to a new 'security' feature" problem.

Since the only solution was to disable the firewall completely on the database server, and since this is not something we are going to ask our clients to do, I rolled back the change that added System.Transactions to the project. Right now, we're going with the assumption that the timeout errors were a problem with QA guy's machine, as it only happens when everything is running all in the process space of his primary machine. If he moves anything to a VPC (even just breaking it in two pieces, whether the web service ends up with the client or the database), it runs fine; and installing everything on the demo machine (which is actually older, less-performing hardware) also doesn't have the issue.

There go my plans for cleaning up the code, too.