Everything is being closed. Also, I have tried
processing the mails, then not performing a DeleteAll()
until before the next mail processing 15 seconds later
and it still hangs up. It works as it is as long as I
include the GC.Collect() call.
Source code:
using System;
using System.Data;
using System.IO;
using System.Text;
using CDO;
using System.Configuration;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace MailService
{
/// <summary>
/// Contains methods used for copying e-mail
messages from a drop folder to
/// the appropriate recipients' inboxes.
/// </summary>
public class SmtpReceive:IDisposable
{
private String _dropDirectory =
@"C:\Inetpub\mailroot\Drop";
private String _tempDirectory =
@"C:\Inetpub\mailroot\Temp";
private String _badmailDirectory =
@"C:\Inetpub\mailroot\Badmail";
private String _mailboxDirectoryPrefix =
@"C:\Inetpub\mailroot\Mailbox\";
private String _mailboxDirectorySuffix =
@"\inbox";
private String _emailSuffix
= "@myDomain.net";
private EventLog log;
private String _machineName = "MYMACHINE";
// Pointer to an external unmanaged
resource.
private IntPtr handle;
// Track whether Dispose has been called.
private bool disposed = false;
/// <summary>
/// Default constructor.
/// </summary>
public SmtpReceive()
{
this.handle = handle;
log = new EventLog("Application",
_machineName, "MailService.exe:SMTPReceive");
}
/// <summary>
/// Checks to see if the specified path
exists; if not, create it.
/// </summary>
/// <param name="directoryPath">Path to
be validated/created.</param>
private void ValidateDirectory(String
directoryPath)
{
try
{
DirectoryInfo di = new
DirectoryInfo(directoryPath);
if(!di.Exists)
Directory.CreateDirectory(directoryPath);
}
catch(Exception ex)
{
log.WriteEntry("Error in
ValidateDirectory: " + ex.Message);
}
}
/// <summary>
/// Gets all the email addresses in the
drop directory and delivers them
/// to the recipients.
/// </summary>
public void Receive()
{
ValidateDirectory(_tempDirectory);
ValidateDirectory
(_badmailDirectory);
//move emails to a temp directory
so we know that no more will be added
//during processing:
FileMove(_dropDirectory,
_tempDirectory);
ProcessMails();
DeleteTempFiles();
}
private void ProcessMails()
{
CDO.DropDirectory drop = new
CDO.DropDirectory();
CDO.IMessages imsg;
imsg = drop.GetMessages
(_tempDirectory);
try
{
for(int i=1; i <=
imsg.Count; i++)
{
string fileName =
imsg.get_FileName(i);
string[]
toAddresses = null;
string[]
ccAddresses = null;
string[]
bccAddresses = null;
try
{
//get
email addresses to send to
toAddresses = imsg[i].To.Split(Convert.ToChar
(","));
ccAddresses = imsg[i].CC.Split(Convert.ToChar
(","));
bccAddresses = imsg[i].BCC.Split(Convert.ToChar
(","));
//get rid
of extra whitespace and other unneeded characters
FixArrayStrings(ref toAddresses);
FixArrayStrings(ref ccAddresses);
FixArrayStrings(ref bccAddresses);
}
catch
{
//bad
mail, drop in BadMail directory
string
badMailPath = _badmailDirectory + @"\" + Path.GetFileName
(fileName);
FileInfo
fi1 = new FileInfo(fileName);
FileInfo
fi2 = new FileInfo(badMailPath);
// Create
the file and clean up handles.
using
(FileStream fs = fi1.Create()) {}
//Ensure
that the target does not exist.
fi2.Delete
();
//Copy
the file.
fi1.CopyTo
(badMailPath,true);
}
//copy email file
to imail folders
//Send "To":
if(toAddresses !=
null)
{
foreach
(string s in toAddresses)
{
CopyMail(fileName, s);
}
}
if(ccAddresses !=
null)
{
//Send "CC":
foreach
(string s in ccAddresses)
{
CopyMail(fileName, s);
}
}
if(bccAddresses !
= null)
{
//Send "BCC":
foreach
(string s in bccAddresses)
{
CopyMail(fileName, s);
}
}
}
}
catch(Exception ex)
{
log.WriteEntry("Error in
ProcessMails: " + ex.Message);
}
finally
{
int iRefCount =
Marshal.ReleaseComObject( drop );
Marshal.ReleaseComObject
(imsg);
/*
* THIS IS THE CALL
TO GC.Collect() THAT SOLVES THE PROBLEM:
*/
GC.Collect();
}
}
/// <summary>
/// Delete temporary files after
processing
/// </summary>
private void DeleteTempFiles()
{
CDO.DropDirectory drop = new
CDO.DropDirectory();
try
{
drop.GetMessages
(_tempDirectory).DeleteAll();
}
catch(Exception ex)
{
log.WriteEntry("Error in
DeleteTempFiles: " + ex.Message);
}
finally
{
int iRefCount =
Marshal.ReleaseComObject( drop );
}
}
/// <summary>
/// Copy file from drop directory to
recipient's inbox
/// </summary>
/// <param name="fileName">Name of the
file to copy</param>
/// <param name="recipient">Email address
of the recipient</param>
private void CopyMail(string fileName,
string recipient)
{
try
{
string userID =
recipient.Substring(0, (recipient.Length -
_emailSuffix.Length));
string suffix =
recipient.Substring(recipient.Length -
_emailSuffix.Length);
if(suffix != _emailSuffix)
return;
string mailbox =
_mailboxDirectoryPrefix + userID +
_mailboxDirectorySuffix;
string inboxPath =
Path.Combine(mailbox, Path.GetFileName(fileName));
FileInfo fi1 = new
FileInfo(fileName);
//check to see if mailbox
exists, create if not
ValidateDirectory
(mailbox);
fi1.CopyTo(inboxPath,
true);
fi1 = null;
}
catch(Exception ex)
{
log.WriteEntry("Error in
CopyMail: " + ex.Message);
}
}
/// <summary>
/// Trims all whitespace from each string
in the array, converts all characters
/// to lowercase and extracts the e-mail
address from the field.
/// </summary>
/// <param name="arr">The array to be
cleansed.</param>
private void FixArrayStrings(ref string[]
arr)
{
try
{
if((arr.Length == 1) &&
(arr[0].Length == 0))
{
arr = null;
return;
}
for(int i = 0; i <
arr.Length; i++)
{
arr[i] = arr
[i].Trim();
arr[i] = arr
[i].ToLower();
arr[i] = arr
[i].Remove(0, arr[i].IndexOf("<") + 1);
arr[i] = arr
[i].Remove(arr[i].IndexOf(">"), arr[i].Length - arr
[i].IndexOf(">"));
}
}
catch(Exception ex)
{
log.WriteEntry("Error in
FixArrayStrings: " + ex.Message);
}
}
/// <summary>
/// Moves files from one directory to
another
/// </summary>
/// <param name="srcdir">The source
directory</param>
/// <param name="destdir">The destination
directory</param>
private void FileMove(string srcdir,
string destdir)
{
try
{
DirectoryInfo dir;
FileInfo[] files;
string tmppath;
//determine if the
destination directory exists, if not create it
ValidateDirectory
(destdir);
dir = new DirectoryInfo
(srcdir);
//if the source dir
doesn't exist, throw
if (! dir.Exists)
{
throw new
ArgumentException("source dir doesn't exist -> " +
srcdir);
}
//get all files in the
current dir
files = dir.GetFiles();
//loop through each file
foreach(FileInfo file in
files)
{
//create the path
to where this file should be in destdir
tmppath=Path.Combine(destdir,
file.Name);
//copy file to
dest dir
file.MoveTo
(tmppath);
}
//cleanup
files = null;
dir = null;
}
catch(Exception ex)
{
log.WriteEntry("Error in
FileMove: " + ex.Message);
}
}
#region IDisposable Members
/// <summary>
/// Dispose
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
// Check to see if Dispose has
already been called.
if(!this.disposed)
{
CloseHandle(handle);
handle =
IntPtr.Zero;
}
disposed = true;
}
[System.Runtime.InteropServices.DllImport
("Kernel32")]
private extern static Boolean CloseHandle
(IntPtr handle);
/// <summary>
/// Destructor
/// </summary>
~SmtpReceive()
{
Dispose(false);
}
#endregion
}
}
-----Original Message-----
Hello Matt,
I reviewed the complete thread and would like to jump in
to provide someinformation.
Without your complete source code, I have not clear
understanding at thistime. To keep us on the same page about the issue, I
assume the issue asfollows. If I made any misunderstanding, please let me
know.
====
You initialize DropDirectory object to open drop
directory and callGetMessages and get reference to all messages collection
under thedirectory. After that, enumerate all messages under the
directory in thecollection to deal with them one by one, such as rename,
move, delivery,reply or others. After that, you and then perform
deletion by calldeleteall().
At the time, you encournter the error: One or more
messages could not bedeleted.
===
I wonder if all messages are closed before you call
deleteall()? Forexample, if you want to move or copy some messages into
another directory,you may open a file stream to open a message file. Did
you make sure youclose it after completing operation?
Here is simple VB sample to do similiar thing. I know
you are working withC# and I just provided it for your reference.
Dim iDropDir as New CDO.DropDirectory
Dim iMsgs as CDO.IMessages
Dim iMsg as CDO.Message
Dim iStream as ADODB.Stream
Dim strTo as String
Dim ToRecipients as Variant
Dim strEmailName as String
Dim strAccountName as String
Dim strFileName as String
Dim strMailboxDir as String
Set iMsgs = iDropDir.GetMessages
For Each iMsg in iMsgs
strFileName = iMsgs.FileName(iMsg)
' trim to get the short file name
' from the full path
strFileName = Right(strFileName, Len(strFileName) -
InStrRev(strFileName,"\")
)
' Get the To recipients...and assume they are all local
accounts
strTo = iMsg.To
ToRecipients = Split(strTo,",")
Dim j, lpos, rpos, posdiff
' loop through recipients and get account names for each
' Each address will be in either the "Name"
<na**@micrsoft.com> or
' simply <na**@microsoft.com>
' We get the account name by getting the string
' between "<" and "@"
For j = LBound(ToRecipients) to UBound(ToRecipients)
strEmailName = ToRecipients(j)
lpos = InStr(strEmailName,"<")
rpos = InStr(strEmailName,"@")
posdiff = rpos - lpos - 1
strAccountName = Mid(strEmailName,lpos + 1, posdiff)
' For the purposes of this example,
' each account's mailbox directory resides in the
' directory c:\mailboxes. For user Joe, their account
' directory would be c:\mailboxes\joe
strMailboxDir = "c:\mailboxes\" & strAccountName
' Get the message stream
Set iStream = iMsg.GetStream
' write the stream to the user's mailbox directory
' the file name is the same as the one in the drop
directory
iStream.SaveToFile strMailboxDir & "\" & strFileName
iStream.Close
Set iStream = Nothing
Next j
Next iMsg
' once we're done, delete the picked up messages
' this deletes the files from the file system as well.
iMsgs.DeleteAll
Set iMsgs = Nothing
Set iDropDir = Nothing
If my information doesn't help, please provide a
complete repro sample. Imay investigate it by checking its souce code. Thank you!
Regards,
Justin Wan
Microsoft Partner Online Support
This posting is provided "AS IS" with no warranties, and
confers no rights.
.