Content by Category
.NET 1.x
.NET 2.0
.NET 3.0
.NET 3.5
.NET 4.0
.NET 4.5
.NET Assemblies
.NET Framework
.NET Getting Started
Accessibility
ADO.NET
Advertorials
Agile Development
AJAX
Amazon Web Services
Analysis Services
Android
Architecture
Arduino
ASP .NET Web API
ASP.NET
ASP.NET MVC
ASP.NET WebForms
Azure
B2B (Business Integration)
BDD
Big Data
Bing
BizTalk
Book Excerpts
Build and Deploy
Business Intelligence
C#
C++
ClickOnce
Cloud Computing
Code Contracts
CODE Framework Info - non Technical
CODE on the Road!
COM+
Community
Conferences
Continuous Integration
Crystal Reports
CSLA.NET
CSS
Data
Debugger
Design Patterns
Development Process
Display Technologies
Distributed Computing
Document Database
DotNetNuke
DSL
Dynamic Languages
Dynamic Programming
Editorials
Enterprise Services ("COM+")
Entity Framework
Events
Expression Blend
F#
Fox to Fox
Frameworks
Functional Programming
Git
Graphics
HTML 5
Internet Explorer 8.0
Interviews
IOS
iPhone
Iron Ruby
Java
Java Script
JavaScript
jQuery
JSON
Lightswitch
LINQ
Linux
LUA
Mac OS X
MDX
Messaging
Metro
Microsoft Application Blocks
Microsoft Business Rules Framework
Microsoft Dynamics
Microsoft Expression
Microsoft Office
Mobile Development
Mobile PC
Mono
MsBuild
MVVM
MySQL
Network
NHibernate
node.js
NOSQL
Nuget
Object Oriented Development
Objective C
Odata
OLAP
Open Source
Opinion
Opinions
Oracle
ORM
Other Languages
Parallel Programming
Patterns
PHP
Podcasts
Post Mortem
PowerPoint
Print/Output
Prism
Product News
Product Reviews
Project Management
Prolog
Python
Q&A
Rails
Rake
Razor
Reporting Services
REST
RIA Services
Ruby
Ruby on Rails
Scheme
Search
Security
Services
SharePoint
SignalR
Silverlight
SOA
Social Networks
Software & Law
Software Business
Source Control
Speech-Enabled Applications
SQL Server
SQL Server 2000
SQL Server 2005
SQL Server 2008
SQL Server 2012
SQL Server CE/AnyWhere/Mobile/Compact
SSIS
Subversion
Sync Framework
Tablet PC
TDD
Team System
Techniques
Testing and Quality Control
TFS
Tips
TypeScript
UI Design
UML
User Groups
VB Script
VB.NET
Version Control
VFP and .NET
VFP and SQL Server
Virtual Earth
Vista
Visual Basic
Visual Basic 6 (and older)
Visual FoxPro
Visual Studio .NET
Visual Studio 11
Visual Studio 2005
Visual Studio 2008
Visual Studio 2010
Visual Studio 2011
Visual Studio 2012
Visual Studio Tools for Office
VSX
WCF
Web Development (general)
Web Services
WebMatrix
WF
Whitepapers
Windows 7
Windows 8
Windows Azure
Windows Live
Windows Phone 7
Windows Phone SDK
Windows Server
Windows Vista
WinForms
WinRT
Workflow
WPF
XAML
Xiine Documentation
XML
XNA
XSLT



LearnNow


XAMALOT
 


SSWUG

Reader rating:
Click here to read 9 comments about this article.
Article source: CoDe (2007 - Mar/Apr)

E-mail Attachments on the Fly

DISCLAIMER:

Although the technology discussed in this article is interesting—that is, the ability to convert a string into a stream—the usage isn’t correct. Rather than going through all this effort to create an attachment based on a string, you can simply call the Attachment.CreateAttachmentFromString method. The author discovered this after the article went to print, apologizes for his error, and hopes that you find the information in this article interesting, if not completely useful.

You know what drives me nuts (among so many other things)? What makes me crazy, this week, is the requirement, in so many areas of programming, that you must serialize data into a file on disk before you can programmatically work with that data. Don’t believe that this is an issue?

Here’s a challenge for you: Store an image in a database somewhere. Now, using the language of your choice, write code that retrieves that image and creates a new picture box on a slide, in Microsoft PowerPoint, that contains that image. I tried. Perhaps I missed the point, but the only way I could accomplish this task was to store the image into a disk file, and then retrieve the image from the disk file and display it on the slide. Although this isn’t a difficult task, the fact that I have to do it really irks me. Solving the problem this way is slow, totally unscalable, and as far as I can tell, the only way to solve the problem.

Until recent versions of Microsoft Access, taking information in a data structure (like an ADO Recordset) and binding it to controls on a form was next to impossible, as well. Around Access 2000 or so, it became possible to bind controls on a form to an open Recordset, making it almost possible to create Access applications that retrieved data from middle-tier business objects. (The implementation isn’t perfect, but it’s better than nothing.)

The same issues come up when building .NET applications, although almost every method that requires a file name also accepts an in-memory data structure, or some type of stream, from which it can work with data.

Case in point: Recently, a friend was building an application, and he needed to be able to send an e-mail message to a list of recipients with a personalized attachment for each recipient. (No, he’s not building a SPAM engine-he’s simply building an application that can manage a little mailing list. Really.) The problem is that he didn’t want to save each personalized attachment to disk before sending the message, and every technique he found required a file name or a stream when specifying the attachment. He had neither-he had a String instance containing his text. He was well aware that saving each file to disk would cause a serious scalability problem, because he might, at some point, want to host this functionality on a Web site with multiple concurrent users.

There really are two issues here: how to send an e-mail at all from a client application, and once you can send an e-mail message at all, how you can add an attachment without first saving the attachment to disk.

Sending e-mail is simple: in the .NET Framework 2.0, you can use the System.Net.Mail namespace, and its MailMessage and Attachment classes to do the work. In the simplest case, you could write code like this to create a mail message, add an attachment, and send the message. You must fill in all the specific information, including the sender and recipient e-mail addresses, along with the name or IP address of your SMTP server. This code also assumes that you can use your current credentials to authenticate on the SMTP server (this code assumes that you have already added an Imports or using statement for the System.Net.Mail namespace):

[Visual Basic]
Dim msg As New MailMessage( _
 "Sender@sender.com", _
 "Recipient@recipient.com", _
 "Subject text here", _
 "Body text here")
msg.Attachments.Add( _
 New Attachment("C:\Myattachment.txt"))

Dim client As _
 New SmtpClient("Your SMTP Server")
client.UseDefaultCredentials = True
client.Send(msg)

[C#]
MailMessage msg = 
  new MailMessage(
  "Sender@sender.com", 
  "Recipient@recipient.com", 
  "Subject text here", 
  "Body text here");
msg.Attachments.Add(
  new Attachment(
  "C:\\Myattachment.txt"));

SmtpClient client = 
  new SmtpClient("Your SMTP Server");
client.UseDefaultCredentials = true;
client.Send(msg);

If you can’t use your current credentials to authenticate on the SMTP server, you can use code like the following to supply the necessary credentials, rather than setting the UseDefaultCredentials property of the SmtpClient class to True. Supply the SmtpClient.Credentials property before calling the Send method:

[Visual Basic]
client.Credentials = _
 New System.Net.NetworkCredential( _
 "username", "password", "domain")

[C#]
client.Credentials = 
 new System.Net.NetworkCredential( 
 "username", "password", "domain");

This all works fine, and I’m guessing that if you have ever needed to send e-mail, you figured this all out. What if, as I mentioned earlier, you want to create the attachment “on the fly”? That is, you don’t want to attach a text file-instead, you want to take the contents of a string, and attach the contents as a text file without ever saving the file on disk? No problem, you can do that. The trick lies in the overloaded versions of the constructor for the Attachment class. The class provides six overloaded versions. Three versions accept a string (plus possibly other information), where the string represents the name of a file. The other three versions allow you to supply a stream instead-the only trick, then, is to get the contents of the string into a stream. This task isn’t as easy as you might think, however.

You can’t simply convert text from a string into a stream-you must work around the conversion. You can create a new MemoryStream instance, passing to the stream’s constructor the bytes you retrieve from the string itself. Of course, you can’t simply retrieve the bytes from the string-you must use an encoder to do this, and the System.Text class provides several different encoders that can do the work for you. You can use the UTF32Encoding class to do the work for you, using the default encoder (see the documentation for this class for more information on all its behaviors). The GetBytes method of an encoder instance retrieves all the bytes in a specified string, like this:

[Visual Basic]
Dim stream As New MemoryStream( _
 UTF32Encoding.Default.GetBytes(data))

[C#]
MemoryStream stream = new MemoryStream(
 UTF32Encoding.Default.GetBytes(data));

To make it easier for my friend, I created a helper procedure, which creates the stream from the string he supplies, and then adds the attachment to the mail message (this procedure assumes you have added using/Imports statements for the System.IO and System.Text namespaces):

[Visual Basic]
Private Sub AddAttachmentFromStream( _
 ByVal message As MailMessage, _
 ByVal data As String, _
 ByVal attachmentName As String)

  Dim stream As New MemoryStream( _
   UTF32Encoding.Default.GetBytes(data))

  ' Rewind the stream.
  stream.Position = 0

  ' Create a new attachment, and
  ' add the attachment to the supplied
  ' message.
  Dim att As New Attachment( _
   stream, attachmentName)
  message.Attachments.Add(att)
End Sub

[C#]
private void AddAttachmentFromStream(
 MailMessage message,
 String data,
 String attachmentName)
{
  MemoryStream stream = 
    new MemoryStream(
    UTF32Encoding.Default.
    GetBytes(data));

  // Rewind the stream.
  stream.Position = 0;

  // Create a new attachment, and
  // add the attachment to the supplied
  // message.
  Attachment att = new Attachment(
   stream, attachmentName);
  message.Attachments.Add(att);
}

Given this procedure, my friend wrote a test procedure like this, to try out the AddAttachmentFromStream method (with all the confidential information changed, of course):

[Visual Basic]
Dim sw As New StringWriter
' Write your data into the buffer:
sw.WriteLine("This is some text")
sw.WriteLine( _
 "Personalized for a recipient.")

Dim msg As New MailMessage( _
 "someone@somewhere.com", _
 "someone@elsewhere.com", _
 "Attachments on the fly", _
 "Check out the attachment!")
AddAttachmentFromStream(msg, _
 sw.ToString, "Attachment.txt")

Dim client As _
  New SmtpClient("MySMTPServer")
client.UseDefaultCredentials = True
client.Send(msg)

[C#]
StringWriter sw = new StringWriter();
MailMessage msg =
  new MailMessage(
  "someone@somewhere.com",
  "someone@elsewhere.com",
  "Attachments on the fly",
  "Check out the attachment");

// Write your data into the buffer:
sw.WriteLine("This is some text");
sw.WriteLine(
"Personalized for a recipient.");

SmtpClient client =
  new SmtpClient("MySMTPServer");
client.UseDefaultCredentials = true;
client.Send(msg);

To test it out, add the AddAttachmentFromStream method to a project, add the sample code (and modify the e-mail addresses and the SMTP server name), and give it a try. You should easily be able to generate an attachment in memory, without ever saving a text file to disk.

This isn’t brain surgery-it’s hardly even tricky. But it’s never obvious how to convert from a string in memory into a stream, and many methods require you to supply a stream (or a file name). In those cases, if you have a string and need a stream instead, remember the technique shown here; it doesn’t only apply to email attachments. Finally, repeat after me: “I won’t use this power for the forces of evil.” Don’t start your own spamming service-I wouldn’t want to be responsible for that! (And if you find a solution to the PowerPoint challenge, please let me know!)

Ken Getz

&

By: Ken Getz

Ken Getz is a senior consultant with MCW Technologies and splits his time between programming, writing, and training. He specializes in tools and applications written in Visual Studio .NET and Visual Basic. Ken is the author of the highly rated .Finalize() column in CoDe Magazine. He is also the co-author of several best-selling books, including Access 2002 Developer's Handbooks with Paul Litwin and Mike Gunderloy, Visual Basic Language Developer's Handbook with Mike Gilbert, and VBA Developer's Handbook with Mike Gilbert (Sybex). He co-wrote several training courses for Application Developer's Training Company (www.appdev.com ), including VB.NET, ASP.NET, Access 2000 and 97, Visual Basic 6, and Visual Basic 5 seminars. He has also recorded video training for AppDev covering VB.NET, ASP.NET, VB6, Access 2000, and Access 97. Ken is a frequent speaker at technical conferences and spoken often at Microsoft's Tech-Ed conference. Ken's also a technical editor for Access-VB-SQL Advisor magazine and a columnist for Informant Publications' asp.netPRO magazine.

keng@mcwtech.com



How would you rate the quality of this article?
1 2 3 4 5
Poor      Outstanding

Tell us why you rated the content this way. (optional)

Average rating:
1.6 out of 5

293 people have rated this article.

Instantly Search Terabytes Of Text
“Lightning Fast”
– Redmond Mag
“Covers all data
sources” – eWeek
25+ fielded & full-text search options
dtSearch’s own document filters highlight hits in popular file types
Web Spider supports static & dynamic data
APIs for .NET, Java, C++, SQL, etc.
Win / Linux (64-bit & 32-bit)
www.dtSearch.com
 

      AppsWorld Europe

 

SSWUG