Redemption in MS Access / Outlook (trying to include a separate message file in email) - email

This code is in MS Access (2010) VBA, using the Redemption library with Microsoft Outlook 2010.
I had this process working before, but we recently had a Citrix upgrade that I guess reset something in my Outlook and now the process no longer works.
I have a folder of .msg files which are basically pre-made email templates with all the proper formatting, images, text, etc.
This is what I was doing before:
Dim outlookApp As Object, namespace As Object
Dim oItem, MyItem
Set outlookApp = CreateObject("Outlook.Application")
Set namespace = outlookApp.GetNamespace("MAPI")
namespace.Logon
Set MyItem = outlookApp.CreateItemFromTemplate(path_to_dot_msg_file)
'And then there are many calls like this:
MyItem.HTMLBody = Replace(MyItem.HTMLBody, "Dear Person,", "Dear " & name)
'...
Set safeItem = CreateObject("Redemption.SafeMailItem")
Set oItem = MyItem
safeItem.Item = oItem
'this next line displays the email, and as of this line, it looks correct
'safeItem.Display
'but as of this line, the issue occurs
safeItem.HTMLBody = "<p>This is an extra message that shows up before the .msg file</p>" & safeItem.HTMLBody
safeItem.Recipients.ResolveAll
safeItem.Send
Now when the email is sent, the .msg contents aren't present at all -- the only thing that shows up is the "extra message" that I prepended to the HTMLBody.
What do I need to change or update? Is this something I need to change in the code, or in my Outlook settings, etc?
Extra: body insertion:
Function insertStringBodyTag(htmlBody As String, stringToInsert As String)
Dim s As String
Dim i As Integer
s = htmlBody
i = InStr(1, s, "<body")
i = InStr(i, s, ">")
s = Left(s, i) & stringToInsert & Right(s, Len(s) - i)
insertStringBodyTag = s
End Function
'Called with safeItem.htmlBody = insertStringBodyTag(safeItem.htmlBody, prefix_string)

You cannot concatenate 2 HTML strings and expect a valid HTML string back - the two must be merged - find the position of the "<body"substring in the original HTML body, then find the positon of the following ">" (this way you take care of the body element with attributes), then insert your HTML string following that ">".

Related

Automate Outlook Emails with Attachments in Excel

I have an Excel spreadsheet with the following 5 columns:
Invoice Number, 2) Company, 3) Primary Email address, 4) Secondary Email address(es), 5) Account Number
I also have a folder that contains invoices. Each invoice has the invoice number in its file name -- i.e., Inv_123456.pdf
I want to build an excel macro that -- when I provide a list of invoice number(s) will:
Open an email -- To: <Primary Contact, Cc: <Secondary contacts, and Bcc: <me,
Put the Invoice Number in the subject, and
Go to the folder containing the invoices and attach the corresponding invoice named InvNo_*.pdf, i.e., InvNo_123456.pdf
This is repeated for each invoice number and the email is displayed for review. *Initially, I want to display the email w/attachment until I am comfortable the macro works as expected.
The path to the folder containing the pre-filled invoices is --
C:\Users\christma-2\OneDrive - OurYear2Win\Documents\Clorodet\Invoice Emails\Attachments\Invoice_*.pdf
Following is the macro I've created so far. I would like to pull the invoice with the corresponding invoice number and attach it to the email.
Sub Send_Email_to_List()
Dim OL As Object, MailSendItem As Object
Dim MsgTxt As String
Set OL = CreateObject("Outlook.Application")
For Each xCell In ActiveSheet.Range(Range("C1"), Range("C" & Rows.Count).End(xlUp))
user_email = xCell.Value
user_subject = "Subject Line for the Email"
user_msg = "Thank You For Submitting this email"
Set MailSendItem = OL.CreateItem(olMailItem)
With MailSendItem
.Subject = user_subject
.Body = user_msg
.To = user_email
.CC = " "
.Bcc = "clorodet20607#aol.com"
'I need help getting the correct attachment, putting the invoice number in the subject, and cc'ing the secondary contacts
.Attachments.Add ("C:\Users\christma-2\OneDrive - OurYear2Win\Documents\Clorodet\Invoice Emails\Attachments\W1\???.pdf")
.Display
End With
Next xCell
Set OL = Nothing
End Sub
Find the corresponding contact's email address -- To: <Primary Contact, Cc: <Secondary contacts, and Bcc: <me,
You can use the CreateRecipient method creates a Recipient object. The name of the recipient; it can be a string representing the display name, the alias, or the full SMTP email address of the recipient. So, there is no need to search for the contact.
Sub ResolveName()
Dim myNamespace As Outlook.NameSpace
Dim myRecipient As Outlook.Recipient
Dim CalendarFolder As Outlook.Folder
Set myNamespace = Application.GetNamespace("MAPI")
Set myRecipient = myNamespace.CreateRecipient("Eugene Astafiev")
myRecipient.Resolve
If myRecipient.Resolved Then
Call ShowCalendar(myNamespace, myRecipient)
End If
End Sub
Sub ShowCalendar(myNamespace, myRecipient)
Dim CalendarFolder As Folder
Set CalendarFolder = myNamespace.GetSharedDefaultFolder(myRecipient, olFolderCalendar)
CalendarFolder.Display
End Sub
You can get a Contact instance by using the following sequence of calls:
recipient.AddressEntry.GetContact()
The Outlook object model supports three main ways of customizing the message body:
The Body property returns or sets a string representing the clear-text body of the Outlook item.
The HTMLBody property of the MailItem class returns or sets a string representing the HTML body of the specified item. Setting the HTMLBody property will always update the Body property immediately. For example:
Sub CreateHTMLMail()
'Creates a new e-mail item and modifies its properties.
Dim objMail As Outlook.MailItem
'Create e-mail item
Set objMail = Application.CreateItem(olMailItem)
With objMail
'Set body format to HTML
.BodyFormat = olFormatHTML
.HTMLBody = "<HTML><BODY>Enter the message text here. </BODY></HTML>"
.Display
End With
End Sub
The Word object model can be used for dealing with message bodies. See Chapter 17: Working with Item Bodies for more information.
Note, the MailItem.BodyFormat property allows you to programmatically change the editor that is used for the body of an item.

XLSX file via OpenXml SDK Both Valid and Invalid

I have a program which exports a System.Data.DataTable to an XLSX / OpenXml Spreadsheet. Finally have it mostly working. However when opening the Spreadsheet in Excel, Excel complains about the file being invalid, and needing repair, giving this message...
We found a problem with some content in . Do you want us to
try to recover as much as we can? If you trust the source of the
workbook, clik Yes.
If I click Yes, it comes back with this message...
Clicking the log file and opening that, just shows this...
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<logFileName>error268360_01.xml</logFileName>
<summary>Errors were detected in file 'C:\Users\aabdi\AppData\Local\Temp\data.20190814.152538.xlsx'</summary>
<repairedRecords>
<repairedRecord>Repaired Records: Cell information from /xl/worksheets/sheet1.xml part</repairedRecord>
</repairedRecords>
</recoveryLog>
Obviously, we don't want to deploy this into a production environment like this. So I've been trying to figure out how to fix this. I threw together a quick little sample to validate the XML and show the errors, based on this link from MSDN. But when I run the program and load the exact same XLSX document that Excel complains about, the Validator comes back saying that the file is perfectly Valid. So I'm not sure where else to go from there.
Any better tools for trying to validate my XLSX XML? Following is the complete code I'm using to generate the XLSX file. (Yes, it's in VB.NET, it's a legacy app.)
If I comment out the line in the For Each dr As DataRow loop, then the XLSX file opens fine in Excel, (just without any data). So it's something with the individual cells, but I'm not really DOING much with them. Setting a value and data type, and that's it.
I also tried replacing the For Each loop in ConstructDataRow with the following, but it still outputs the same "bad" XML...
rv.Append(
(From dc In dr.Table.Columns
Select ConstructCell(
NVL(dr(dc.Ordinal), String.Empty),
MapSystemTypeToCellType(dc.DataType)
)
).ToArray()
)
Also tried replacing the call to Append with AppendChild for each cell too, but that didn't help either.
The zipped up XLSX file (erroring, with dummy data) is available here:
https://drive.google.com/open?id=1KVVWEqH7VHMxwbRA-Pn807SXHZ32oJWR
Full DataTable to Excel XLSX Code
#Region " ToExcel "
<Extension>
Public Function ToExcel(ByVal target As DataTable) As Attachment
Dim filename = Path.GetTempFileName()
Using doc As SpreadsheetDocument = SpreadsheetDocument.Create(filename, DocumentFormat.OpenXml.SpreadsheetDocumentType.Workbook)
Dim data = New SheetData()
Dim wbp = doc.AddWorkbookPart()
wbp.Workbook = New Workbook()
Dim wsp = wbp.AddNewPart(Of WorksheetPart)()
wsp.Worksheet = New Worksheet(data)
Dim sheets = wbp.Workbook.AppendChild(New Sheets())
Dim sheet = New Sheet() With {.Id = wbp.GetIdOfPart(wsp), .SheetId = 1, .Name = "Data"}
sheets.Append(sheet)
data.AppendChild(ConstructHeaderRow(target))
For Each dr As DataRow In target.Rows
data.AppendChild(ConstructDataRow(dr)) '// THIS LINE YIELDS THE BAD PARTS
Next
wbp.Workbook.Save()
End Using
Dim attachmentname As String = Path.Combine(Path.GetDirectoryName(filename), $"data.{Now.ToString("yyyyMMdd.HHmmss")}.xlsx")
File.Move(filename, attachmentname)
Return New Attachment(attachmentname, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
End Function
Private Function ConstructHeaderRow(dt As DataTable) As Row
Dim rv = New Row()
For Each dc As DataColumn In dt.Columns
rv.Append(ConstructCell(dc.ColumnName, CellValues.String))
Next
Return rv
End Function
Private Function ConstructDataRow(dr As DataRow) As Row
Dim rv = New Row()
For Each dc As DataColumn In dr.Table.Columns
rv.Append(ConstructCell(NVL(dr(dc.Ordinal), String.Empty), MapSystemTypeToCellType(dc.DataType)))
Next
Return rv
End Function
Private Function ConstructCell(value As String, datatype As CellValues) As Cell
Return New Cell() With {
.CellValue = New CellValue(value),
.DataType = datatype
}
End Function
Private Function MapSystemTypeToCellType(t As System.Type) As CellValues
Dim rv As CellValues
Select Case True
Case t Is GetType(String)
rv = CellValues.String
Case t Is GetType(Date)
rv = CellValues.Date
Case t Is GetType(Boolean)
rv = CellValues.Boolean
Case IsNumericType(t)
rv = CellValues.Number
Case Else
rv = CellValues.String
End Select
Return rv
End Function
#End Region
For anyone else coming in and finding this, I finally tracked this down to the Cell.DataType
Setting a value of CellValues.Date will cause Excel to want to "fix" the document.
(apparently for dates, the DataType should be NULL, and Date was only used in Office 2010).
Also, if you specify a DataType of CellValues.Boolean, then the CellValue needs to be either 0 or 1. "true" / "false" will also cause Excel to want to "fix" your spreadsheet.
Also, Microsoft has a better validator tool already built for download here:
https://www.microsoft.com/en-us/download/details.aspx?id=30425

Ms Access - Button with code doesn't work to send email

I have this code set in access, but no email is sending upon clicking the button on the form. I have outlook open. When i click the button on the form, i can't see anything that actually happens. I want the email address to be equal to the value in [text1], and I am trying to make the subject include a fixed message plus the input from [text2]. Even without these variables, I can't get this to work
Public Sub Command495_Click()
Dim mailto As String
Dim ccto As String
Dim bccto As String
mailto = [text1]
ccto = ""
bccto = ""
emailmsg = "trial"
mailsub = [text2] & ", Does this work?"
On Error Resume Next
DoCmd.SendObject acSendNoObjectType, , acFormattxt, mailto, ccto, bccto, mailsubj, emailmsg, True
End Sub
I have checked to make sure the onclick property shows event procedure. I am stuck, please help!
Here are a few suggestions and a modified version of your code.
ALWAYS use Option Explicit and compile your module before testing. You had a number of variables that were not defined and incorrect spelling of some options.
NEVER bypass errors when testing (get rid of your "On Error Resume Next") That's why you never saw an error.
Look for every place I entered ">>>" and address that issue.
Always explicitly define your variables and use the proper Type. Removes all doubt of what/where something is.
Option Compare Database
Option Explicit
Public Sub Command495_Click()
Dim mailto As String
Dim ccto As String
Dim bccto As String
Dim emailmsg As String
Dim mailsub As String
mailto = [Text1] ' >>> Where is [Text1]?? Remove for testing
ccto = ""
bccto = ""
emailmsg = "trial"
mailsub = [Text2] & ", Does this work?" ' >>> Where is [Text2]?? Remove for testing
' >>> Bad idea to ignore errors when testing!!
On Error Resume Next
'>>> Following line had: (1) 'acSendNoObjectType' which is incorrect; (2) mailsubj, which is undefined
DoCmd.SendObject acSendNoObject, , acFormatTXT, mailto, ccto, bccto, mailsub, emailmsg, True
End Sub

How to retrieve the value of an Input field and use it to modify a placeholder in a LibreOffice Basic macro?

I've spent two days on this and I'm still not able to figure it out 8-)
I have a LibreOffice Writer document with some Placeholders (Insert -> Fields -> More Fields -> Functions -> Placeholder -> Image) and Input fields (Insert -> Fields -> More Fieds -> Functions -> Input field) and I need to retrieve the value of an Input field and use it to replace a specified Placeholder in the same document.
To be more precise. I have an Input field where I enter for example 123
and somewhere in the document is a button, which triggers a macro, and this macro should:
retrieve the current value of the specified (named?) Input field ("123"),
"replace" a specified (named?) Placeholder with an image loaded from http://domain.tld/image/123.png
Is this somehow possible? Would be great, because I'm trying to to insert externally generated barcodes into my document...
These are both "Text fields", and some information and macro examples are in Andrew Pitonyak's book OpenOffice Macros Explained (available as a free pdf download from http://www.pitonyak.org/oo.php). The wiki page also has some good background.
Form controls (from the toolbar "Form controls") are named, so they have an advantage when working with macros. Text fields, however - the kind you have in your document - are not named, so you have to cycle through all the fields in a document, or highlight a particular run of text and cycle through the field within the highlighted area to find the one you are after. The Pitonyak document has examples of both methods.
Assuming the document has only one input field, this StarBasic code will print its current value:
Sub DisplayFields
Dim oEnum As Object
Dim oField As Object
oEnum = ThisComponent.getTextFields().createEnumeration()
Do While oEnum.hasMoreElements()
oField = oEnum.nextElement()
If oField.getPresentation(True) = "Input field" Then
Print "Input field contents: " & oField.getPresentation(False)
Exit Do
End If
Loop
End Sub
As far as I can tell, there is no API to replace a placeholder with its designated content. There might be a way with the dispatcher - the list of dispatch commands tantalizingly includes "FieldDialog" - but I wasn't able to find any documentation or examples.
I think what you'd have to do is find the field, put your cursor there, insert the image, then delete the placeholder field. Some more StarBasic code (again, assuming there's only a single placeholder field in the document):
Sub InsertImage
Dim oEnum As Object
Dim oField As Object
Dim oAnchor As Object
Dim oText As Object
Dim oCursor As Object
Dim FileName As String
Dim FileURL As String
Dim objTextGraphicObject As Object
oEnum = ThisComponent.getTextFields().createEnumeration()
Do While oEnum.hasMoreElements()
oField = oEnum.nextElement()
If oField.getPresentation(True) = "Placeholder" Then
oAnchor = oField.Anchor
oText = oAnchor.getText()
oCursor = oText.createTextCursorByRange(oAnchor.getEnd)
FileName = "C:\after zoo.JPG"
FileURL = convertToURL(FileName)
objTextGraphicObject = ThisComponent.createInstance("com.sun.star.text.TextGraphicObject")
REM Optional to set the size
' Dim objSize as New com.sun.star.awt.Size
' objSize.Width = 3530
' objSize.Height = 1550
' objTextGraphicObject.setSize(objSize)
objTextGraphicObject.GraphicURL = FileURL
oText.insertTextContent(oCursor.Start, objTextGraphicObject, false)
oField.dispose()
Exit Do
End If
Loop
End Sub

sending outlook based email in VBScript - error (sfile as string) line?

im trying to send an email from a VBScript, it will eventually be added into a currently working script as an else if (if this is possible).
im getting an error at line 23 character 32?
Dim outobj, mailobj
Dim strFileText
Dim objFileToRead
Set outobj = CreateObject("Outlook.Application")
Set mailobj = outobj.CreateItem(0)
strFileText = GetText("C:\test\test 2.txt")
With mailobj
.To = "user#user.com"
.Subject = "Testmail"
.Body = strFileText
.Display
End With
Set outobj = Nothing
Set mailobj = Nothing
End Sub
Function GetText(sFile as String) As String
Dim nSourceFile As Integer, sText As String
nSourceFile = FreeFile
Open sFile For Input As #nSourceFile
sText = Input$(LOF(1), 1)
Close
GetText = sText
End Function
what do i need to add to get line 23 to work and the script to finally do what i need it to, i have copied most of this script from elsewhere due to a sincere lack of VBscripting knowledge?
Take a look at the Using Automation to Send a Microsoft Outlook Message article. It provides a sample code and describes all the required steps for sending emails.
Try this: remove the GetText function entirely, and replace the line
strFileText = GetText("C:\test\test 2.txt")
with
Set fso = CreateObject("Scripting.FileSystemObject")
strFileText = fso.OpenTextFile("C:\test\test 2.txt").ReadAll