I have an issue where I'm sending a PDF file as an attachment, but when the email arrives with the client, it's arriving as a file with a name very similar to the MIME type, but with the correct content. I specify an attachment file name of "Statement.pdf", but it arrives as "application_pdf.txt" which then confuses the receiver as it doesn't open as a PDF. The mail sending is handled by a Windows Service written in Visual Basic.
Here is the main bit of code that actually sends it:
Dim SmtpServer As New SmtpClient()
Dim mail As New MailMessage()
SmtpServer.Credentials = New Net.NetworkCredential(mailAddress, mailPassword)
SmtpServer.Port = mailPort
SmtpServer.Host = mailServer
SmtpServer.EnableSsl = mailSSL
SmtpServer.DeliveryMethod = SmtpDeliveryMethod.Network
mail = New MailMessage()
If fromName <> "" Then mailName = fromName
mail.From = New MailAddress(fromAddr, mailName)
mail.IsBodyHtml = True
mail.To.Add(toAddr)
If replyTo <> "" Then
mail.ReplyToList.Add(replyTo)
End If
If cc <> "" Then
mail.CC.Add(cc)
End If
mail.Subject = subject
mail.Body = body
If attached <> "" And attachMIME <> "" And attachname <> "" Then
mail.Attachments.Add(Attachment.CreateAttachmentFromString(attached, attachMIME))
mail.Attachments.Last().ContentDisposition.FileName = attachname
End If
SmtpServer.Send(mail)
The various variables in here are passed in from the calling code and I'm confident that they're correct, in that if the password, port etc were incorrect the email wouldn't send. In particular the attachMIME is "application/pdf" which appears to be correct according to pdfa.org.
The PDF is generated on another machine, and passed to this one using FTP in binary mode. This service then reads the PDF into a string and passes it into the mail sending function:
Dim attachBytes() As Byte = Nothing
attachBytes = My.Computer.FileSystem.ReadAllBytes(FileDir & "\" & msg.attachFile)
mailAttachFile = ""
For Each attbyt As Byte In attachBytes
mailAttachFile &= Chr(attbyt)
Next
I thought I'd cracked it because I was originally using ReadAllText which strips out any non-printable characters, and I imagined that the mail transport somewhere was checking the PDF for validity, seeing the unprintable characters had changed and presuming it was some sort of mal-formed file. Unfortunately changing to ReadAllBytes didn't seem to help, and the PDF file is still arriving as a file named "attachment_pdf.txt", still with the correct content. If I save the file from my email client and then rename it, it displays perfectly as a PDF in Acrobat Reader. My customer is receiving emails from other companies with PDF attachments, so it's not just that his email provider doesn't trust PDFs.
I don't simply use AddAttachment(filename) to load the attachment because the code works in two ways - one where the service downloads the email files from a remote FTP server, and the other (this one) where the files are sent to the machine running the service and the service opens them locally. In order to keep the actual mail sending the same, loading the files is done further "up" the code and the resulting email message and attachment passed in here via a function call. So by the time I get to the first code block I posted above, the code doesn't know (or care) where the message and attachment came from.
Is there anything glaringly obvious in what I have posted that might be causing this issue? I should add that I have the same code running on another machine, using gmail as the mail transport (which this one does not) and the other method I mentioned above and it sends a PDF attachment every day without issue.
(Edited to clarify that the attachment file contents are not changing, just the attachment name is changing, which confuses the receiver.)
Related
I work at a Company that gets requests we filter in terms of
being eligibile for financing from our financing partner
requiring more information from the enquirer
There is a lot of monotonous work, in copy pasting email replies.
I looked into creating a Quick Action in Outlook, but because our mother company does not allow certain freedoms, like the Font has to be specifically Segoe Ui Light etc. I could not use this, so I thought about writing a macro.
I intended for a macro button to:
Open a new Reply email, replying to all in the original mail.
In this new email text body, use a template email that I already made and saved as a template. (This way it saved the Font, size and other formatting.)
Put in the original Sender and CC'ed mail addresses as well as the Subject from the original mail.
And then display the email, so I could make edits if I wanted to before sending.
Sub ReplyGewerbeanmeldung()
Dim origEmail As MailItem
Dim replyEmail As MailItem
Set origEmail = Application.ActiveWindow.Selection.Item(1)
Set replyEmail = Application.CreateItemFromTemplate(" "C:\Users\XYZ\AppData\Roaming\Microsoft\Templates\ReplyGewerbeanmeldung.oft"\ReplyGewerbeanmeldung.oft")
replyEmail.To = origEmail.Sender
replyEmail.CC = origEmail.CC
replyEmail.Subject = origEmail.Subject
replyEmail.HTMLBody = replyEmail.HTMLBody & origEmail.Reply.HTMLBody
replyEmail.Display
End Sub
First of all, it seems you need to correct the file path to the template message. The following string is not a valid file path:
" "C:\Users\XYZ\AppData\Roaming\Microsoft\Templates\ReplyGewerbeanmeldung.oft"\ReplyGewerbeanmeldung.oft"
Try to use the following string instead:
Set replyEmail = Application.CreateItemFromTemplate("C:\Users\XYZ\AppData\Roaming\Microsoft\Templates\ReplyGewerbeanmeldung.oft")
You can read more about that in the How To: Create a new Outlook message based on a template article.
Anyway, creating items from a template will not preserve the original message body. Moreover, in Outlook you will not get any visual appearance that a particular items was replied. So, you need to call the ReplyAll method on the original item in Outlook to avoid this artefacts in Outlook.
You can create a new mail item, but only for copying the message body response which is required to paste into the reply. The NameSpace.OpenSharedItem method can be used to to open iCalendar appointment (.ics) files, vCard (.vcf) files, and Outlook message (.msg) files. You may consider using it instead of creating a new item based on the template to grab the message body from there.
I'm trying to create a VBA code (I'm relatively new at this) that will attach a PDF to an email. I've gotten everything to work (the email is created, the file attached, and when I press 'send' the email arrives at it's destination) but when I use olByValue, 1 the file name appears as text at the end of the email after sending (in addition to the actual attachment being displayed as it should be along the top of the email).
I am trying to find a way to hide that text. I tried to use olByValue, 0 but part of our protocols at work includes manually QCing all emails before sending so that there's no possibility of accidentally sending Client A's data to Client B (the macro doesn't include the .Send command for this reason). Is there a way to be able to review the PDF while it's attached to the email before sending but not display the file name as text after sending?
I'm using Excel for 365 to create the email body and to send the data over to Outlook 365.
The line of code that pertains to the attachment is below. Thanks for any help and please let me know if I wasn't clear on something.
If Range("AD45") = "Update" And Range("AJ36") = "1" And Range("AJ37") = "Yes" Then
.Attachments.Add Range("AB26").Value, olByValue, 0
.Body = Range("Z80").Value & vbNewLine & vbNewLine & vbNewLine & vbNewLine
End If
The location is determined by the message format.
The Rich Text format supports in-line attachments and thus the attachments show up in the body of the message. Plain Text and HTML formatted emails do not support this and show the attachments in a separate line under the message header but above the message body. See Attachments show up in the message body for more information.
For example, before attaching files to the email you need to set the BodyFormat property which sets an OlBodyFormat constant indicating the format of the body text. :
With objMail
'Set body format to HTML
.BodyFormat = olFormatHTML
.HTMLBody = "<HTML><H2>The body of this message will appear in HTML.</H2><BODY>Type the message text here. </BODY></HTML>"
.Display
End With
I currently have two Lotus Notes databases, each with their own email addresses associated with them. As expected, when I send an email through the first database to my gmail account, it shows up as "From: notesAccount1#db1.com" and when I send using the second database, the message shows up as "From: notesAccount2#db2.com" in my gmail.
I have working code that opens up the second database, searches the inbox for an email containing a certain keyword, and extracts an email address from that email. It then creates a new document in that second database, inserts the recipients name, subject, body, etc., sends the email, and saves it to my sent folder. Everything works smoothly up to this point.
However, when I send an email from the second database to my gmail account using this VBA method, the email shows up in my gmail as "From: notesAccount1#db1.com" - the email associated with the first database.
I can't figure out why this is happening. Pretty limited knowledge of the interactions between VBA and Lotus Notes, and Lotus Notes servers/databases in general. The first database is technically my default one that only I have access to and the second database was added later and multiple people have access to it. I don't know if that's relevant.
Would appreciate any help! Thanks.
Note: This code was copied and adapted from several sources, including some on SO, IBM and other Notes sources, and anything else Google threw my way, including
http://www.fabalou.com/vbandvba/lotusnotesmail.asp
http://www-01.ibm.com/support/docview.wss?uid=swg21178583
Code: (This will have to be adapted as I have taken out server names and mail file names)
Sub ReadNotesEmail()
Dim sess As Object
Dim db As Object
Dim folder As Object
Dim docNext As Object
Dim memoSenders As Variant
Dim newEmail As Object
Dim view As Object
Dim entry As Object
Dim entries As Object
Dim templateEmail As Object
Dim mailServer As String
Dim mailFile As String
Dim folderName As String
Dim todayDate As String
Dim memoBody As String
Dim senderEmail As String
Dim emailStartPos As Integer
Dim emailEndPos As Integer
'This program will search a particular folder in a Notes database that I designate.
'It will search that folder for emails that contain certain key words. Once it finds
'an email that fits, it will grab the sender's email address (written in the body, not
'in the 'from') and send them an email.
'Name of folder to search for emails
folderName = "($Inbox)"
'Create a Lotus Notes session and open it (will require password)
Set sess = CreateObject("Lotus.NotesSession")
sess.Initialize ("")
'Set the mail server, mail file, and database. This will be the tricky part as I need this to
'look at the second mail server as opposed to the default mail server of jdyagoda
Set db = sess.GETDATABASE("***name of second Notes server***", "***name of second mail file***")
'Open the mail database in notes
If Not db.IsOpen = True Then
Call db.Open
End If
Set folder = db.GetView(folderName)
'Now look through the emails one at a time with a loop that ends when no emails are left.
'If an email contains the key word, look for the email address of the person who submitted
'the contact-us form. It follows the string "Email:" and preceeds
'the string "Phone:".
Set doc = folder.GetFirstDocument
Do Until doc Is Nothing
Set docNext = folder.GETNEXTDOCUMENT(doc)
memoBody = LCase(doc.GetItemValue("body")(0))
If (memoBody Like "*") Then 'This is where you designate the keyword
'Here's where you extract the email address - taken out for the purpose of this SO question
'senderEmail = testName#test.com
'Now create a new email to the intended recipient
Set newEmail = db.CREATEDOCUMENT
Call newEmail.ReplaceItemValue("Form", "Memo")
Call newEmail.ReplaceItemValue("SendTo", senderEmail)
Call newEmail.ReplaceItemValue("Subject", "Thank you for your email")
Call newEmail.ReplaceItemValue("body", "Test Body 1. This is a test.")
newEmail.SAVEMESSAGEONSEND = True
'Send the new email
Call newEmail.ReplaceItemValue("PostedDate", Now()) 'Gets the mail to appeaer in the sent items folder
Call newEmail.SEND(False)
End If
Set doc = docNext
Loop
End Sub
Notes will normally send the mail using the email address for the ID you use to login. So if you login using notesAccount1/Domain, then all emails will be coming from notesAccount1#example.com.
If you want to fake the sender, you need to use an undocumented method: inject the email directly into mail.box.
You should not attempt to do this unless you really know what you are doing.
I have posted code on my blog for a mail notification class, it supports this work-around to set the sender on outgoing emails. You can find the latest code at http://blog.texasswede.com/updated-mailnotification-class-now-with-html-email-support-and-web-links/
I've got an emailing system in my application which I have used fine and have seen it working.
The customer has also managed to send emails using the program, however, once they've paid for the application, they're then selling it on to other customers.
They've just taken it in to test with the first customer and they're having troubles sending emails, so I investigated the error log and saw the following message:
The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.57 SMTP; Client was not authenticated to send anonymous mail during MAIL FROM [BN6PR2201CA0027.namprd22.prod.outlook.com]
Now, after Googling this exact error message, the top result was this question, in which it's clear to see that the OP was trying to send a message from an email address that was hard-coded as "emailaddress". However, that isn't the case for me.
My code is as follows:
recipient = eMail
Smtp_Server.UseDefaultCredentials = False
Smtp_Server.Credentials = New Net.NetworkCredential(senderAdd, senderPass)
Smtp_Server.EnableSsl = False
Smtp_Server.Host = SMTPserver
AddHandler Smtp_Server.SendCompleted, AddressOf sendComplete
e_mail = New MailMessage()
e_mail.From = New MailAddress(senderAdd)
e_mail.DeliveryNotificationOptions = DeliveryNotificationOptions.OnSuccess
e_mail.To.Add(eMail)
e_mail.Subject = subj
e_mail.IsBodyHtml = False
e_mail.Body = bod
Smtp_Server.SendAsync(e_mail, userState)
Is there anything in here which would be causing this error? If so, what is it?
The variables are all set from a database table, and if there are any null values then the system will pop a message box to alert the user of this and then exit the subroutine and not send the email, so it's not an issue with null values - The only thing I can think of is that the credentials are wrong, but they've supposedly been verified by 3 different people as correct.
You might need to specify the domain. Use this constructor of the NetworkCredential class and pass in the domain.
Smtp_Server.Credentials = New Net.NetworkCredential(senderAdd, senderPass, "expectedDomainName")
Difficult to say for sure though because we can't reproduce this issue under your same conditions.
I have a windows service that sends out emails by retriving the records from the database. The service account Windows Service is running under, is a Local admin on that machine. The issue i am having is somehow the windows service manages to send out some emails with pdf attachements that exist on the local server where windows service is located and for most of them i get an error message: Invalid Mail Attachment and having real difficulties what could be causing it? any idea on where should i start looking please?
Thanks
Try
' Initialize new mail message class
Dim objEmailMessage As New System.Net.Mail.MailMessage(EmailOutboxEntity.EmailFrom, EmailOutboxEntity.EmailTo)
' Set the email parameters
objEmailMessage.Subject = EmailOutboxEntity.EmailSubject
objEmailMessage.Body = EmailOutboxEntity.EmailBody
' Check if attachments have been specified
If Not EmailOutboxEntity.TestOriginalFieldValueForNull(EmailOutboxFieldIndex.EmailAttachements) Then
' Get an array of attachment file names to send
Dim arrAttachment As String() = Split(EmailOutboxEntity.EmailAttachements, CONST_AttachmentSeparator)
' Step through each filename and attach it to the email
For Each strAttachment As String In arrAttachment
' Attach the current file to the email
objEmailMessage.Attachments.Add(New System.Net.Mail.Attachment(strAttachment))
Next
End If
' Set the SMTP server
Dim mailServer As New System.Net.Mail.SmtpClient(pstrSMTPServer)
' Send the message
mailServer.Send(objEmailMessage)
Catch errException As Exception
' Throw an exception indicating the email failed to send
Throw New EmailOutboxManagerException(errException.Message, "Test Failed to send email, got the following error instead:")
End Try
Sorry Guys, as i have figured out the answer and it was my fault because i was running two different versions of the windows service on different servers and they were both picking up the attachments from the database and the path existed on one server where the files were saved and not on the other server and that's why some of the emails were managed to be sent.