I'm using vb.net to send email via .MSG file, I've tried with .OFT, both using createitemfromtemplate.
The emails will send, no problem. Works great. The only issue I have is anytime I restart, I have to resave the .msg or .oft files as the same file names in order for them to send again, otherwise it won't work anymore.
Any ideas as to why this is or how to fix this?
Example:
Dim omsg As Object
omsg = Outl.CreateItemfromtemplate("Custom Two.msg")
omsg.To = (TextBox1.Text)
omsg.Subject = (TextBox2.Text)
omsg.Display(False) 'will display message to user
Someone suggested adding the files into memory before the application loads to correct this.. but I'm not 100% sure how to do this, other than it goes in the load events.. Any ideas?
The answer I found to be easiest for this is:
Dim filelist() As String = Directory.GetFiles(Application.StartupPath)
For Each File In filelist
If File.Contains(".oft") Or File.Contains(".msg") Then
Dim temp1 As String = File.Replace(Application.StartupPath & "\", String.Empty)
If File.Contains(".oft") Then
ComboBox1.Items.Add(temp1)
ElseIf File.Contains(".msg") Then
ComboBox1.Items.Add(temp1)
End If
End If
Instead of trying to read them into a list one by one with names, linking them dynamically seems to fit better and execute without an issue.
Related
how do I add a path to a code where "HERE_HAS_TO_BE_A_PATH" is. When I do, Im getting an error message. The goal is to be able to specific the path where is the final text file saved.
Thanks!
Here is a code:
Dim newFile As IO.StreamWriter = IO.File.CreateText("HERE_HAS_TO_BE_A_PATH")
Dim fix As String
fix = My.Computer.FileSystem.ReadAllText("C:\test.txt")
fix = Replace(fix, ",", ".")
My.Computer.FileSystem.WriteAllText("C:\test.txt", fix, False)
Dim query = From data In IO.File.ReadAllLines("C:\test.txt")
Let name As String = data.Split(" ")(0)
Let x As Decimal = data.Split(" ")(1)
Let y As Decimal = data.Split(" ")(2)
Let z As Decimal = data.Split(" ")(3)
Select name & " " & x & "," & y & "," & z
For i As Integer = 0 To query.Count - 1
newFile.WriteLine(query(i))
Next
newFile.Close()
1) Use a literal string:
The easiest way is replacing "HERE_HAS_TO_BE_A_PATH" with the literal path to desired output target, so overwriting it with "C:\output.txt":
Dim newFile As IO.StreamWriter = IO.File.CreateText("C:\output.txt")
2) Check permissions and read/write file references are correct:
There's a few reasons why you might be having difficulties, if you're trying to read and write into the root C:\ directory you might be having permissions issues.
Also, go line by line to make sure that the input and output files are correct every time you are using one or the other.
3) Make sure the implicit path is correct for non-fully qualified paths:
Next, when you test run the program, it's not actually in the same folder as the project folder, in case you're using a relative path, it's in a subfolder "\bin\debug", so for a project named [ProjectName], it compiles into this folder by default:
C:\path\to\[ProjectName]\bin\Debug\Program.exe
In other words, if you are trying to type in a path name as a string to save the file to and you don't specify the full path name starting from the C:\ drive, like "output.txt" instead of "C:\output.txt", it's saving it here:
C:\path\to\[ProjectName]\bin\Debug\output.txt
To find out exactly what paths it's defaulting to, in .Net Framework you can check against these:
Application.ExecutablePath
Application.StartupPath
4) Get user input via SaveFileDialogue
In addition to a literal string ("C:\output.txt") if you want the user to provide input, since it looks like you're using .Net Framework (as opposed to .Net Core, etc.), the easiest way to set a file name to use in your program is using the built-in SaveFileDialogue object in System.Windows.Forms (like you see whenever you try to save a file with most programs), you can do so really quickly like so:
Dim SFD As New SaveFileDialog
SFD.Filter = "Text Files|*.txt"
SFD.ShowDialog()
' For reuse, storing file path to string
Dim myFilePath As String = SFD.FileName
Dim newFile As IO.StreamWriter = IO.File.CreateText(myFilePath) ' path var
' Do the rest of your code here
newFile.Close()
5) Get user input via console
In case you ever want to get a path in .Net Core, i.e. with a console, the Main process by default accepts a String array called args(), here's a different version that lets the user add a path as the first parameter when running the program, or if one is not provided it asks the user for input:
Console.WriteLine("Hello World!")
Dim myFilePath = ""
If args.Length > 0 Then
myFilePath = args(0)
End If
If myFilePath = "" Then
Console.WriteLine("No file name provided, please input file name:")
While (myFilePath = "")
Console.Write("File and Path: ")
myFilePath = Console.ReadLine()
End While
End If
Dim newFile As IO.StreamWriter = IO.File.CreateText(myFilePath) ' path var
' Do the rest of your code here
newFile.Close()
6) Best practices: Close & Dispose vs. Using Blocks
In order to keep the code as similar to yours as possible, I tried to change only the pieces that needed changing. Vikyath Rao and Mary respectively pointed out a simplified way to declare it as well as a common best practice.
For more information, check out these helpful explanations:
Can any one explain why StreamWriter is an Unmanaged Resource. and
Should I call Close() or Dispose() for stream objects?
In summary, although streams are managed and should garbage collect automatically, due to working with the file system unmanaged resources get involved, which is the primary reason why it's a good idea to manually dispose of the object. Your ".close()" does this. Overrides for both the StreamReader and StreamWriter classes call the ".dispose()" method, however it is still common practice to use a Using .. End Using block to avoid "running with scissors" as Enigmativity puts it in his post, in other words it makes sure that you don't go off somewhere else in the program and forget to dispose of the open filestream.
Within your program, you could simply replace the "Dim newFile As IO.StreamWriter = IO.File.CreateText("C:\output.txt")" and "newFile.close()" lines with the opening and closing statements for the Using block while using the simplified syntax, like so:
'Dim newFile As IO.StreamWriter = IO.File.CreateText(myFilePath) ' old
Using newFile As New IO.StreamWriter(myFilePath) ' new
Dim fix As String = "Text from somewhere!"
newFile.WriteLine(fix)
' other similar operations here
End Using ' new -- ensures disposal
'newFile.Close() ' old
You can write that in this way. The stream writer automatically creates the file.
Dim newFile As New StreamWriter(HERE_HAS_TO_BE_A_PATH)
PS: I cannot mention all these in the comment section as I have reputations less than 50, so I wrote my answer. Please feel free to tell me if its wrong
regards,
vikyath
I wrote a simple program written to collect files, send the files, then delete said files. I am sending them via Email using System.Net.Mail
If Label6.Text = "" Then
mail.Attachments.Add(New Attachment(zipPath))
End If
'Enables SSL, if required
ssl = Provider.ssl
If skipAhead = True Then
ssl = True
End If
If ssl = True Then
SmtpServer.EnableSsl = True
End If
'Sends the email
SmtpServer.Send(mail)
'Allows the user to either keep testing, or quit.
If skipAhead = True Then
My.Computer.FileSystem.DeleteFile(unalteredPath)
My.Computer.FileSystem.DeleteFile(unalteredPath1)
My.Computer.FileSystem.DeleteFile(zipPath)
Else
Dim keepOpen As Integer = MsgBox("The Email was sent. You can keep testing if you would like to. Press ok to close, and cancel to keep testing", MsgBoxStyle.OkCancel)
If keepOpen = 1 Then
Close()
End If
End If
As seen in line 2, the attachment is added to the email, and I do not attempt to delete the attachment until after the email is sent, however when the code is running, it throws an error that the file is being used by another process.
I am also wondering if this could be lingering from the .zip being created itself. Here is the code that does that:
Public Sub Zipping()
'Copies files to the folder where they will be zipped from
My.Computer.FileSystem.CopyFile(unalteredPath, outputs & "\ExIpOutput.txt")
My.Computer.FileSystem.CopyFile(unalteredPath1, outputs & "\IpConfig.txt")
'Deletes the old output files
My.Computer.FileSystem.DeleteFile(unalteredPath)
My.Computer.FileSystem.DeleteFile(unalteredPath1)
'Starts the zip Sub
ZipFile.CreateFromDirectory(outputs, zipPath, CompressionLevel.Fastest, True)
My.Computer.FileSystem.DeleteDirectory(outputs, FileIO.DeleteDirectoryOption.DeleteAllContents)
End Sub
Here is the CreateFromDirectory sub:
Public Shared Sub CreateFromDirectory(sourceDirectoryName As String, destinationArchiveFileName As String, compressionLevel As Compression.CompressionLevel, includeBaseDirectory As Boolean)
End Sub
Is there something I'm missing here, or do I need to have the program sleep for a bit to let the email send, then delete the .zip file?
You can load the file into an array: File.ReadAllBytes(String) Method.
Then get a MemoryStream from that: How do I convert struct System.Byte byte[] to a System.IO.Stream object in C#?
And finally, you can use a MemoryStream for an attachment: Attach a file from MemoryStream to a MailMessage in C#.
As the data to be sent is in memory, you should be able to delete the file. Note that if there is a crash, the data is gone.
The examples are in C#, but if you have problems using the methods in VB.NET, please edit your question to show how far you've got and tell us what the problem is.
A better solution to this issue is to dispose the Attachment object that is locking the file. Any object you create that has a Dispose method should have that method called when you're done with the object and an Attachment is no different.
Dim fileAttachment As Attachment
If Label6.Text = "" Then
fileAttachment = New Attachment(zipPath)
mail.Attachments.Add(fileAttachment)
End If
'...
SmtpServer.Send(mail)
If fileAttachment IsNot Nothing Then
fileAttachment.Dispose()
End If
I am writing a vba script to open a particular mail from outlook and then open a link in that mail.
So far I have only achieved the first part. How do I get vba to test which part of the body is a hyper link and to open it?
Dim stringsearch As String
stringsearch = oMsg.Body
So now the searchstring contains the body text of the mail.
I know that the link will always begin with the phrase "SearchID" and will always be the last line of the mail.
Any help/suggestions/links are very appreciated.
This will find the "SearchId" within the stringsearch and extract everything after it into "link".
dim linkLoc as Integer
linkLoc = instr(1, stringsearch, "SearchID")
dim link as string
link = mid(stringsearch, linkLoc + 8)
I am writing a small program in which user will select set of file (mostly .CSV) files and my program will search through them and find required data.
It's working for up to 300 files, but after that its not working. It's giving me an error:
InvalidOperationExceprion was Unhandaled
Too Many files are selected. Select Fewer files and try again.
What should i do?
Like Eric Walker said, open file dialog works with 1,000's and 1,000's of files, there is no reason why it would stop at 300.
The best way to loop though files/folders to get info is to use the .GetFiles() method
Dim OFD As New FolderBrowserDialog
If OFD.ShowDialog = DialogResult.OK Then
For Each f In Directory.GetFiles(OFD.SelectedPath)
If Path.GetExtension(f) = ".txt" Path.GetExtension(f) = ".csv" Then
Dim reader As String() = File.ReadAllLines(f)
For each line as String in reader
DoSomethingAwesome(line)
Next
End If
Next
End If
This will cycle through every file in a certain Directory.
Now if you would like to cycle through every file in a file dialog, then you would use this.
Dim OFD As New OpenFileDialog()
OFD.Multiselect = True
If OFD.ShowDialog = DialogResult.OK Then
For Each f In OFD.FileNames
If Path.GetExtension(f) = ".txt" Path.GetExtension(f) = ".csv" Then
Dim reader As String() = File.ReadAllLines(f)
For Each line As String In reader
DoSomethingAwesome(line)
Next
End If
Next
End If
Give one of these a try depending on your preference.
As a side note, for future posts - please post your attempted code or more details on what you are trying to accomplish and where you are having trouble. Frankly, Im surprised you weren't downvoted (very surprised, people on SO can be ruthless). Just a friendly tip.
I have a fairly straight forward peice of code that just tries to set the default saved directory for a standard .net save dialogue to a specific folder. If that folder doesn't exist, it sets it to the desktop.
This works fine for everyone but one user who is getting the following error:
Could not find special directory 'Desktop'
How is that even possible?
'Check if folder exists
If Not IO.Directory.Exists(strDirectory) Then
strDirectory = FileIO.SpecialDirectories.Desktop
If Not IO.Directory.Exists(strDirectory) Then
strDirectory = IO.Directory.GetCurrentDirectory
End If
End If
'Show save file dialogue.
Dim folderDlg As New Windows.Forms.FolderBrowserDialog
folderDlg.RootFolder = Environment.SpecialFolder.Desktop
folderDlg.SelectedPath = strDirectory
folderDlg.ShowNewFolderButton = True
How about:
strDirectory = _
Environment.GetFolderPath(Environment.SpecialFolder.Desktop).ToString()
I use GetFolderPath() to get "My Documents" and it works fine (I don't ever have to think about it).