Why is CF FTP transfer speed multiple times slower than standard FTP? - ftp

I have a ColdFusion application that I use to transfer files between our development and production servers. The code that actually sends the files is as follows:
ftp = new Ftp();
ftp.setUsername(username);
ftp.setPassword(password);
ftp.setServer(server);
ftp.setTimeout(1800);
ftp.setConnection('dev');
ftp.open();
ftp.putFile(transferMode="binary",localFile=localpath,remoteFile=remotepath);
ftp.close(connection='dev');
When sending a file using the above code, I cap out at just under 100KB/s(monitored via FileZilla on the receiving server). If I send the exact same file using the Windows command-line FTP tool, my speeds are upwards of 1000KB/s.
I created a brand new file with nothing but the code above and that has no effect on the transfer speed, so I know it has nothing to do with the surrounding code in the original application.
So, what could be causing these abysmally low speeds?
Edit: All tests are being done transferring files from my production server to my development server. I also tried using the <cfftp> tag instead of cfscript, and I have the same results.
Edit #2: I ended up using cfexecute, the code is as follows:
From my FTP script:
public function sendFiles(required string localpath, required string remotepath) {
this.writeFtpInstructions(localpath);
exe = "C:\Windows\system32\ftp.exe";
params = "-s:" & request.localapproot & "/" & "upload.txt";
outputfile = request.localapproot & '/ftp.log';
timeout = 120;
Request.cliExec(exe,params,outputfile,timeout);
}
public function writeFtpInstructions(required string localpath) {
instructions = request.localapproot & "/" & "upload.txt";
crlf = chr(13) & chr(10);
data = "";
data &= "open " & this.server & crlf;
data &= this.username & crlf;
data &= this.password & crlf;
data &= "cd " & request.remoteapproot & crlf;
data &= "put " & localpath & crlf;
data &= "quit";
FileWrite(instructions, data);
}
The cliExec() function(necessary to create a wrapper since there is no equivalent of cfexecute in cfscript):
<cffunction name="cliExec">
<cfargument name="name">
<cfargument name="arguments">
<cfargument name="outputfile">
<cfargument name="timeout">
<cfexecute
name="#name#"
arguments="#arguments#"
outputFile="#outputfile#"
timeout="#timeout#" />
</cffunction>

With my experience using cfftp on CF9, it was impossible to transfer larger files. If you view the active transfers on the FTP server side, you will notice that the transfers start out at top speed, but as more & more data is transmitted the speeds keep dropping. After 100 MB had been transfered, the reduction started to become very drastic, until they eventually reached a single digit crawl. Eventually the transfer timed out & failed. I was trying to work with a 330 MB file & found it impossible to transfer using cfftp. The cfexecute was not an option for me using the standard windows ftp.exe, because it doesn’t seem to support SFTP.
I ended up seeking out an external java class to use through coldfusion & settled on JSch (http://www.jcraft.com/jsch/). Ironically, CF9 appears to use a variation of this class for CFFTP (jsch-0.1.41m.jar), but the results are much different using this latest downloaded version (jsch-0.1.45.jar).
Here is the code that I put together for a proof of concept:
<cfscript>
stAppPrefs = {
stISOFtp = {
server = 'sftp.server.com',
port = '22',
username = 'youser',
password = 'pa$$w0rd'
}
};
/* Side-Load JSch Java Class (http://www.jcraft.com/jsch/) */
try {
// Load Class Using Mark Mandel's JavaLoader (http://www.compoundtheory.com/?action=javaloader.index)
/*
Add Mark's LoaderClass To The ColdFusion Class Path Under CF Admin:
Java and JVM : ColdFusion Class Path : C:\inetpub\wwwroot\javaloader\lib\classloader-20100119110136.jar
Then Restart The Coldfusion Application Service
*/
loader = CreateObject("component", "javaloader.JavaLoader").init([expandPath("jsch-0.1.45.jar")]);
// Initiate Instance
jsch = loader.create("com.jcraft.jsch.JSch").init();
}
catch(any excpt) {
WriteOutput("Error loading ""jsch-0.1.45.jar"" java class: " & excpt.Message & "<br>");
abort;
}
/* SFTP Session & Channel */
try {
// Create SFTP Session
session = jsch.getSession(stAppPrefs.stISOFtp.username, stAppPrefs.stISOFtp.server, stAppPrefs.stISOFtp.port);
// Turn Off & Use Username/Password
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword(stAppPrefs.stISOFtp.password);
session.connect();
// Create Channel To Transfer File(s) On
channel = session.openChannel("sftp");
channel.connect();
}
catch(any excpt) {
WriteOutput("Error connecting to FTP server: " & excpt.Message & "<br>");
abort;
}
// Returns Array Of Java Objects, One For Each Zip Compressed File Listed In Root DIR
// WriteDump(channel.ls('*.zip'));
// Get First Zip File Listed For Transfer From SFTP To CF Server
serverFile = channel.ls('*.zip')[1].getFilename();
/* Debug */
startTime = Now();
WriteOutput("Transfer Started: " & TimeFormat(startTime, 'hh:mm:ss') & "<br>");
/* // Debug */
/* Transfer File From SFTP Server To CF Server */
try {
// Create File On Server To Write Byte Stream To
transferFile = CreateObject("java", "java.io.File").init(expandPath(serverFile));
channel.get(serverFile, CreateObject("java", "java.io.FileOutputStream").init(transferFile));
// Close The File Output Stream
transferFile = '';
}
catch(any excpt) {
WriteOutput("Error transfering file """ & expandPath(serverFile) & """: " & excpt.Message & "<br>");
abort;
}
/* Debug */
finishTime = Now();
WriteOutput("Transfer Finished: " & TimeFormat(finishTime, 'hh:mm:ss') & "<br>");
expiredTime = (finishTime - startTime);
WriteOutput("Duration: " & TimeFormat(expiredTime, 'HH:MM:SS') & "<br>");
WriteOutput("File Size: " & NumberFormat(Evaluate(GetFileInfo(ExpandPath(serverFile)).size / 1024), '_,___._') & " KB<br>");
WriteOutput("Transfer Rate: " & NumberFormat(Evaluate(Evaluate(GetFileInfo(ExpandPath(serverFile)).size / 1024) / Evaluate(((TimeFormat(expiredTime, 'H') * 60 * 60) + (TimeFormat(expiredTime, 'M') * 60) + TimeFormat(expiredTime, 'S')))), '_,___._') & " KB/Sec <br>");
/* // Debug */
channel.disconnect();
session.disconnect();
</cfscript>
Results:
Transfer Started: 09:37:57
Transfer Finished: 09:42:01
Duration: 00:04:04
File Size: 331,770.8 KB
Transfer Rate: 1,359.7 KB/Sec
The transfer speed that was achieved is on par with what I was getting using the FileZilla FTP Client & manually downloading. I found this method to be a viable solution for the inadequacy of cfftp.

I have been looking and I dont have an answer about why it is slower. But, in theory, you should be able to use cfexecute to do this through the windows command line. You might could even create a batch file and do it in one call.

Related

ASP CDO issue with read receipt request

I am have problems with an older classic ASP application where read receipts are employed in the code. This particular routine has been used for a number of years successfully but recently we have migrated to a new server with Windows 2008 r2, IIS 7.5 and SmarterMail 11.07 client. Now whenever the application attempts to send a server generated email, the SmarterMail logs are showing it successfully receives and authenticates the submission, but seems to terminate or abort the connection without cause and won't send the email without any errors. I'm at a loss here because like I stated, this routine has worked without problems for some time now and if we don't select the "read-receipt" option in the ASP application the email distributes just fine. I have included a shortened version of the code below and mainly looking for validation that the code for all intended purposes should work as is and if anyone may know of similar issues related to this within SmarterMail itself, like some kind of default security setting I am unaware of. Incidentally, if we manually use the SmarterMail webmail interface, we can successfully send mail with read receipts, so I know it should be possible.
- Thank you kindly!
Code Example
set Mail = Server.CreateObject("CDO.Message")
'Basic configuration
Mail.AutoGenerateTextBody = 0
Mail.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserver") = strHost
Mail.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
Mail.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = strPort
Mail.Configuration.Fields.Update
Mail.Fields("urn:schemas:mailheader:X-Mailer") = "Custom EMailer"
Mail.Fields.update
'Priority
Mail.Fields("urn:schemas:mailheader:X-Priority") = emPriority
Mail.Fields("urn:schemas:mailheader:X-MSMail-Priority") = emPriorityTxt
Mail.Fields("urn:schemas:httpmail:importance") = emPriority
Mail.Fields.update
'Addressing
With Mail
.From = strFrom
.ReplyTo = strReplyTo
.To = strTo
.CC = strCc
.BCC = strBCc
End With
'Attachments
if len(sfls) > 0 then
if instr(1,sfls,",",1) > 0 then
strAttachments = split(sfls,",",-1,1)
else
strAttachments = sfls
end if
if isarray(strAttachments) then
for x = 0 to ubound(strAttachments)
Mail.AddAttachment strAttachments(x)
next
else
Mail.AddAttachment strAttachments
end if
end if
'Body
Mail.Subject = strSubject
if isHTML then
Mail.HTMLBody = strBody
else
Mail.TextBody = strBodyTxt
end if
'###################################################################
'If this section is included the email will not send, times out or
'connection is terminated, according to the SmarterMail logs
'###################################################################
' Read/Delivery Receipt
if isRead then
Mail.Fields("urn:schemas:mailheader:disposition-notification-to") = rrReplyTo
Mail.Fields("urn:schemas:mailheader:return-receipt-to") = rrReplyTo
Mail.DSNOptions = 14
Mail.Fields.Update
end if
'###################################################################
'Send Message
strErr = ""
bSuccess = False
On Error Resume Next
Mail.Send
If Err <> 0 Then
strErr = Err.Description
else
bSuccess = True
End If
set Mail = nothing
============================================================

JMeter asserting a response has been successfully downloaded

I am using JMeter to test some of the functionality on my site. Through using the Save Responses to a file element, I have been able to successfully issue a request to download a pdf through JMeter. However, I am curious if there is an assertion to check that a file has actually downloaded (and if possible, is in the format I specified!). I know I can simply look at the file, but I'm hoping to make this more automated. I have checked "Save Successful Responses Only," but I want to ensure a response has actually been saved.
I think you need to use a Beanshell Assertion for this.
Example code to check file presence, size and content type is below:
File file = new File("/path/to/downloaded/file");
//check file existence
if (!file.exists())
{
Failure = true;
FailureMessage = "File " + file.getName() + " does not exist";
}
//check file size
long expectedSize = SampleResult.getBodySize();
long actualSize = file.length();
if (expectedSize != actualSize)
{
Failure = true;
FailureMessage = "Actual file size differs from expected. Expected: " + expectedSize + " and got: " + actualSize ;
}
//check content type
String expectedType = SampleResult.getContentType();
String actualType = file.toURI().toURL().openConnection().getContentType();
if (!expectedType.equals(actualType))
{
Failure = true;
FailureMessage = "Response types are different. Expected: " + expectedType + " and got: " + actualType;
}
See How to Use JMeter Assertions in 3 Easy Steps guide for more information on JMeter Assertions superpower.

Script Works on Win 7, Not on Server 2003

I have a script that is rather simple, it boots up WinSCP and checks the directory for a file that starts with "TSA". If the file exists, it exits, if it does not exist, it transfers over a new file.
Its up and running on my Windows 7 machine, that is where i created it - but when i transfer it over to my server [windows server 2003] it never finds the file.
My script:
var FILEPATH = "../zfinance/TSA";
// Session to connect to
var SESSION = "someplace#somewhere.com";
// Path to winscp.com
var WINSCP = "c:\\program files\\winscp\\winscp.com";
var filesys = WScript.CreateObject("Scripting.FileSystemObject");
var shell = WScript.CreateObject("WScript.Shell");
var logfilepath = filesys.GetSpecialFolder(2) + "\\" + filesys.GetTempName() + ".xml";
var p = FILEPATH.lastIndexOf('/');
var path = FILEPATH.substring(0, p);
var filename = FILEPATH.substring(p + 1);
var exec;
// run winscp to check for file existence
exec = shell.Exec("\"" + WINSCP + "\" /log=\"" + logfilepath + "\"");
exec.StdIn.Write(
"option batch abort\n" +
"open \"" + SESSION + "\"\n" +
"ls \"" + path + "\"\n" +
"exit\n");
// wait until the script finishes
while (exec.Status == 0)
{
WScript.Sleep(100);
WScript.Echo(exec.StdOut.ReadAll());
}
if (exec.ExitCode != 0)
{
WScript.Echo("Error checking for file existence");
WScript.Quit(1);
}
// look for log file
var logfile = filesys.GetFile(logfilepath);
if (logfile == null)
{
WScript.Echo("Cannot find log file");
WScript.Quit(1);
}
// parse XML log file
var doc = new ActiveXObject("MSXML2.DOMDocument");
doc.async = false;
doc.load(logfilepath);
doc.setProperty("SelectionNamespaces",
"xmlns:w='http://winscp.net/schema/session/1.0'");
doc.setProperty("SelectionLanguage", "XPath");
var nodes = doc.selectNodes("//w:file/w:filename[starts-with(#value, '" + filename + "')]");
if (nodes.length > 0)
{
WScript.Echo("File found");
WScript.Quit(0);
}
else
{
WScript.Echo("File not found");
WScript.Quit(1);
}
After much investigation, i think i've found the piece of code that does not function properly:
// parse XML log file
var doc = new ActiveXObject("MSXML2.DOMDocument.6.0");
doc.async = false;
doc.load(logfilepath);
doc.setProperty("SelectionNamespaces",
"xmlns:w='http://winscp.net/schema/session/1.0'");
The only problem is, i have no idea why. The log file at this point should be written over with the xml code, but this does not happen.
Thanks in advance for any help.
And the answer is........... WinSCP on Windows Server 2003 was WAY out of date. So out of date that the log was completely different from one version to the next. Updated and VIOLA! Problem solved. Thanks for your help.
Maybe you need to install MSXML2.DOMDocument.6.0
http://msdn.microsoft.com/en-us/library/windows/desktop/cc507436%28v=vs.85%29.aspx
If you open up regedit and look for "MSXML2.DOMDocument.6.0" does it find it? If so maybe security settings for the script need to be set in order to be able to create an activeX object.
What can you see when you put some stuff in try catch?
try{
//stuff
}catch(e){
WScript.Echo(e.message);
}

UNC path can be mapped from command line but not from .NET Console application

How can I make the .NET code map the Z: drive to the UNC path for account SVNdatamgmt?
I'm trying to map a local drive to a network UNC path within a .NET console application. The code seems to work from the command line for both the service account (#2 and #3) and with my credentials (#4). But when running from the Console application using .NET source code, the service account doesn't work (#5), but my credentials do work (#6).
Last night, I noticed that I got an error (#1). After waiting 30 minutes, it worked. So you can ignore #1. I thought I'd mention it, in case it gives a clue as to what is happening.
The console application is running as an administrator on a Windows Server 2008 box. Both SVCdatamgmt and macgyver are administrators on this machine. The commands are also being run on this same machine.
========================================================================
1.) This didn’t work last night:
C:>net use z: \\uwhc-sas2\SASHIMC /USER:SVCdatamgmt thepassword
System error 1909 has occurred.
The referenced account is currently locked out and may not be logged on to.
========================================================================
2.) Waited 30 minutes and then this worked (without domain):
C:>net use z: \\uwhc-sas2\SASHIMC /USER:SVCdatamgmt thepassword
The command completed successfully.
========================================================================
3.) This also works (with domain):
C:>net use z: \\uwhc-sas2\SASHIMC /USER:UWHIS\SVCdatamgmt thepassword
The command completed successfully.
========================================================================
4.) This also works with my credentials:
C:>net use z: \\uwhc-sas2\SASHIMC /USER:macgyver thepassword
The command completed successfully.
========================================================================
5.) .NET code that maps drive. SVCdatamgmt credentials do not work.
public static void MapNetworkDriveToUNC()
{
var command = #"net use " + mapDrive + " " + uncPath + " " + uncUser + " " + uncPass;
ExecuteCommand(command, 10000);
}
public static void UnmapNetworkDriveToUNC()
{
var command = "net use " + mapDrive + " /delete";
ExecuteCommand(command, 5000);
}
========================================================================
6.) .NET code that maps drive. My credentials work (macgyver)
-- same code as #5 --
========================================================================
FYI: before running each command above, I have to disconnect (unmap) the drive using this code...
C:\>net use z: /delete
z: was deleted successfully.
I was looking for the command to map UNC Path to Network Drive from C# and I implemented this and works great. Its too late but may be helpful to someone in future:
public static bool MapDrivetoUNC(string DriveName, string Path)
{
try
{
bool isMapped = true;
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
//p.StartInfo.RedirectStandardError = true;
//p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "net.exe";
p.StartInfo.Arguments = " use " + DriveName + ": " + '"' + Path + '"';
p.Start();
p.WaitForExit();
//str errMsg = p.StandardError.ReadToEnd();
// similar for erroutput ..
isMapped = true;
}
catch(Exception ex)
{
Utility.logError(ex);
isMapped = false;
}
return isMapped;
}

Save mail to msg file using EWS API

I'm using Exchange Web Services Managed API 1.1 to connect to Exchange server 2010 and then find out new emails received. Now I want to save a copy of the .msg file to a folder on the disk.
I do not want to use any paid third party to integrate.
Any help will be appreciated.
If you are happy to save into the .eml format instead, it can be done very easily just using EWS and no third party libraries. The .eml file will contain all the same information and can be opened by Outlook in the same way as .msg (and also by other programs).
message.Load(new PropertySet(ItemSchema.MimeContent));
MimeContent mc = message.MimeContent;
FileStream fs = new FileStream("c:\test.eml", FileMode.Create);
fs.Write(mc.Content, 0, mc.Content.Length);
fs.Close();
Cleaned up code:
message.Load(new PropertySet(ItemSchema.MimeContent));
var mimeContent = message.MimeContent;
using (var fileStream = new FileStream(#"C:\Test.eml", FileMode.Create))
{
fileStream.Write(mimeContent.Content, 0, mimeContent.Content.Length);
}
There is no native support for MSG files using EWS. It's strictly an Outlook format.
The MSG spec is published at http://msdn.microsoft.com/en-us/library/cc463912%28EXCHG.80%29.aspx. It's a little complicated to understand, but do-able. You would need to pull down all of the properties for the message and then serialize it into an OLE structured file format. It's not an easy task.
In the end, you are probably better off going with a 3rd party library otherwise it might be a big task to accomplish.
You can easily access the MIME contents of the message through message.MimeContent and save the message as an EML file. The latest (2013 and 2016) versions of Outlook will be able to open EML files directly.
message.Load(new PropertySet(ItemSchema.MimeContent));
MimeContent mimcon = message.MimeContent;
FileStream fStream = new FileStream("c:\test.eml", FileMode.Create);
fStream.Write(mimcon.Content, 0, mimcon.Content.Length);
fStream.Close();
If you still need to convert to the MSG format, you have a few options:
MSG file format is documented - it is an OLE store (IStorage) file. See https://msdn.microsoft.com/en-us/library/cc463912(v=exchg.80).aspx
Use a third party MSG file wrapper, such as the one from Independentsoft: http://www.independentsoft.de/msg/index.html. Setting all properties that Outlook expects can be challenging.
Convert EML file to MSG directly using Redemption (I am its author):
set Session = CreateObject("Redemption.RDOSession") set Msg = Session.CreateMessageFromMsgFile("c:\test.msg") Msg.Import("c:\test.eml", 1024) Msg.Save
Keep in mind that MIME won't preserve all MAPI specific properties. You can use the Fast Transfer Stream (FTS) format used by the ExportItems EWS operation (which, just like the MSG format, preserves most MAPI properties). The FTS data can then be converted (without any loss of fidelity) to the MSG format using Redemption (I am its author) - RDOSession.CreateMessageFromMsgFile / RDOMail.Import(..., olFTS) / RDOMail.Save
RDOSession session = new RDOSession(); RDOMail msg = session.CreateMessageFromMsgFile(#"c:\temp\test.msg"); msg.Import(#"c:\temp\test.fts", rdoSaveAsType.olFTS); msg.Save();
This suggestion was posted as a comment by #mack, but I think it deserves its own place as an answer, if for no other reason than formatting and readability of answers vs. comments.
using (FileStream fileStream =
File.Open(#"C:\message.eml", FileMode.Create, FileAccess.Write))
{
message.Load(new PropertySet(ItemSchema.MimeContent));
MimeContent mc = message.MimeContent;
fileStream.Write(mc.Content, 0, mc.Content.Length);
}
If eml format is an option and php is the language use base64_decode on the Mimencontent before save on file.
If using https://github.com/Heartspring/Exchange-Web-Services-for-PHP or https://github.com/hatsuseno/Exchange-Web-Services-for-PHP need to add
$newmessage->mc = $messageobj->MimeContent->_;
on line 245 or 247.
This is how I solved the problem to download from EWS the email message in .eml format via vbs code
' This is the function that retrieves the message:
function CreaMailMsg(ItemId,ChangeKey)
Dim MailMsg
Dim GetItemSOAP,GetItemResponse,Content
LogFile.WriteLine (Now() & "-" & ":CreaMailMsg:ID:" & ItemId)
GetItemSOAP=ReadTemplate("GetItemMsg.xml")
GetItemSOAP=Replace(GetItemSOAP, "<!--ITEMID-->", ItemId)
GetItemSOAP=Replace(GetItemSOAP, "<!--ITEMCHANGEKEY-->", ChangeKey)
LogFile.WriteLine (Now() & ":GetItemSOAP:" & GetItemSOAP)
set GetItemResponse=SendSOAP(GetItemSOAP,TARGETURL,"",USERNAME,PASSWORD)
' Check we got a Success response
if not IsResponseSuccess(GetItemResponse, "m:GetItemResponseMessage","ResponseClass") then
LogFile.WriteLine (Now() & "-" & ":ERRORE:Fallita GetItemMsg:" & GetItemResponse.xml)
Chiusura 1
end if
' LogFile.WriteLine (Now() & "-" & ":DEBUG:riuscita GetItemMsg:" & GetItemResponse.xml)
Content = GetItemResponse.documentElement.getElementsByTagName("t:MimeContent").Item(0).Text
' LogFile.WriteLine (Now() & ":Contenuto MIME" & Content)
CreaMailMsg = WriteAttach2File(Content,"OriginaryMsg.eml")
' MailMsg.close
CreaMailMsg = true
end function
'###########################################################################
' These are the functions the save the message in .eml format
'###########################################################################
function WriteAttach2File(Content,nomeAttach)
Dim oNode,oXML,Base64Decode
' Read the contents Base64 encoded and Write a file
set oXML=CreateObject("MSXML2.DOMDocument")
set oNode=oXML.CreateElement("base64")
oNode.DataType="bin.base64"
oNode.Text = Content
Base64Decode = Stream_Binary2String(oNode.nodeTypedValue,nomeAttach)
Set oNode = Nothing
Set oXML = Nothing
end function
'###########################################################################
function Stream_Binary2String(binary,nomeAttach)
Const adTypeText = 2
Const adTypeBinary = 1
Dim BinaryStream
Set BinaryStream=CreateObject("ADODB.Stream")
BinaryStream.Type=adTypeBinary' Binary
BinaryStream.Open
BinaryStream.Write binary
BinaryStream.Position=0
BinaryStream.Type=adTypeText
BinaryStream.CharSet = "us-ascii"
Stream_Binary2String=BinaryStream.ReadText
'msgbox Stream_Binary2String
BinaryStream.SaveToFile ShareName & "\" & nomeAttach,2
Set BinaryStream=Nothing
end function
If you are going from Outlook's EntryID via VSTO (Hex) to EwsID, you need to look here: http://bernhardelbl.wordpress.com/2013/04/15/converting-entryid-to-ewsid-using-exchange-web-services-ews/
Saved me. I kept getting a "Data is corrupt." message.
You can download all the attachments using EWS API and C# . Below is the example given:
byte[][] btAttachments = new byte[3][]; //To store 3 attachment
if (item.HasAttachments) {
EmailMessage message = EmailMessage.Bind(objService, new ItemId(item.Id.UniqueId.ToString()), new PropertySet(BasePropertySet.IdOnly, ItemSchema.Attachments));
noOfAttachment = message.Attachments.Count;
// Iterate through the attachments collection and load each attachment.
foreach(Attachment attachment in message.Attachments)
{
if (attachment is FileAttachment)
{
FileAttachment fileAttachment = attachment as FileAttachment;
// Load the file attachment into memory and print out its file name.
fileAttachment.Load();
//Get the Attachment as bytes
if (i < 3) {
btAttachments[i] = fileAttachment.Content;
i++;
}
}
// Attachment is an item attachment.
else
{
// Load attachment into memory and write out the subject.
ItemAttachment itemAttachment = attachment as ItemAttachment;
itemAttachment.Load(new PropertySet(EmailMessageSchema.MimeContent));
MimeContent mc = itemAttachment.Item.MimeContent;
if (i < 3) {
btAttachments[i] = mc.Content;
i++;
}
}
}
}
Above code converts all the attachment into bytes. Once you have bytes, you can convert bytes into your required format.
To Convert bytes into files and save in the disk follow the below links:
Write bytes to file
http://www.digitalcoding.com/Code-Snippets/C-Sharp/C-Code-Snippet-Save-byte-array-to-file.html

Resources