The code below reads and inserts the email from lotus notes to an excel sheet. However I would like to read a lotus notes database and copy its content and paste it as a rich text into a word document.
I assume this line of code needs to be modified.
Set nitem = .GetFirstItem("Body")
What would be the best way to go about this?
Public Sub Lotus_Notes_Current_Email4()
Dim NSession As Object 'NotesSession
Dim NUIWorkSpace As Object 'NotesUIWorkspace
Dim NUIdoc As Object 'NotesUIDocument
Dim nitem As Object 'NotesItem
Dim lines As Variant
Set NSession = CreateObject("Notes.NotesSession")
Set NUIWorkSpace = CreateObject("Notes.NotesUIWorkspace")
Set NUIdoc = NUIWorkSpace.CurrentDocument
If Not NUIdoc Is Nothing Then
With NUIdoc.Document
Set nitem = .GetFirstItem("Body")
If Not nitem Is Nothing Then
lines = Split(nitem.Text, vbCrLf)
Sheets(1).Activate
Range("H8").Resize(UBound(lines) + 1, 1).Value = Application.WorksheetFunction.Transpose(lines)
End If
End With
Else
MsgBox "Lotus Notes is not displaying an email"
End If
Set NUIdoc = Nothing
Set NUIWorkSpace = Nothing
Set NSession = Nothing
End Sub
Your assumption is incorrect. Your entire script needs to be rewritten.
If you want to copy the contents of a view, then you need to start by opening a NotesView object. Your current code is opening a NotesDocument object. To get the NotesView, you might want to use the CurrentView property NotesUIWorkspace to get a NotesUIView object, and then use that objects View property.
Once you have the NotesView object, then I'm guessing you might want to want to use the columns property to get at the data, but there are other ways you could go about it. Pretty much no matter what you do, though, you're going to have to handle the formatting of the data on your own.
Related
I am trying to read one pdf and a VBA userform and then fill out another pdf.
I wrote code to read all text in a pdf and then find certain sub strings based on tokens that I can find in the string. It is intended to populate the fields in the destination pdf based on the substrings and check the appropriate text boxes based on the user form. I can get the code to fill the substrings and then save the document, but it won't check the boxes.
Before the code used a AVDoc, but I switched to a JSO because I don't want the pdf to pop up, and the jso avoids that problem.
I tried pdfBool.value = cBool(vbaBool), pdfBool.value = 1, pdfBool.value = "1", jso.setValue("checked"), jso.setValue("yes"), etc.
This code will run without crashing. I reduced the number of variables to one string and one bool for the sake of the example.
Sub main()
‘findString grabs all text from a pdf file. This code works.
Dim mystr As String
If findString(mystr) = False Then
Application.StatusBar = "Cannot find Source PDF"
Exit Sub
End If
Dim mypath As String
mypath = ActiveWorkbook.Path & "\destination.pdf"
Dim aApp As acrobat.AcroApp
Dim pdfDoc As acrobat.CAcroPDDoc
Dim jso As Object
Set aApp = CreateObject("AcroExch.App")
Set pdfDoc = CreateObject("AcroExch.PDDoc")
If pdfDoc.Open(mypath) = True Then
Set jso = pdfDoc.GetJSObject
Dim vbaText As String
Dim vbaBool As String
vbaText = returnString("Token1")
vbaBool = userForm.checkBox1.value
Dim pdfText As Object
Dim pdfBool As Object
Set pdfText = jso.getField("TextField1")
Set pdfBool = jso.getField("CheckBox1")
pdfText.Value = vbaText
pdfBool.Value = vbaBool
'save pdffile
Dim fileSavePath As String
fileSavePath = ActiveWorkbook.Path & "\My Save File.pdf"
pdfDoc.Save PDSaveFull, fileSavePath
'clean up memory
Set pdfDoc = Nothing
Set pdfText = Nothing
Set pdfBool = Nothing
Set jso = Nothing
End If
aApp.Exit
Set aApp = Nothing
Unload userForm1
End Sub
Ok, so after some searching, I have found a solution. Basically, forms created using Living Cycle don't work well with checkboxes. I asked somebody in my organization and they confirmed that Living Cycle was used on forms for a while until we got rid of it. Honestly, I don't know what Living Cycle is, but the solution seemed to work and so I think whatever the issue was related to something called "Living Cycle".
The solution? Redo the pdf form: I exported the pdf to an Encapsulated PostScript file. This stripped away all the fields. After that, I used the prepare form tool which automatically found all the relevant fields. Fortunately, with my pdf, it found all of the fields perfectly, though there was one or two extra ones that I had to delete. The field names and the code need to match so adjustments need to either be made to the PDF or to the code, but once I made that adjustment, everything was perfect.
Try jso.getfield(pdfFieldName).Value = "Yes" or "No". The value is case sensitive so you have to use Yes or No.
I have a script (found on the web and adjusted to my needs) that can access a specific view of Lotus Notes, pick up some info from each email and save any attachment to a given folder. If I want to do this for more views I currently have the names of these views in my worksheet and loop through them.
What I would like to do is to loop through all views and do the same.
I am not a professional developer and not yet entirely familiar working with objects. This problem however is to complicated for me. The Lotus Notes object is also not the easiest to understand.
I am using the following code which of course is part of a larger (working) script. For starters it would be enough to just be able to loop through all views and print the Name of the view. From there on I think I can do the rest myself.
Can anyone adjust the code to make it work.
Public Sub Get_Notes_Email_Text()
Dim NSession As Object 'NotesSession
Dim NMailDB As Object 'NotesDatabase
Dim NDocs As Object 'NotesDocumentCollection
Dim NDoc As Object 'NotesDocument
Dim NNextDoc As Object 'NotesDocument
Dim view As String
'Start a Lotus Notes session
Set NSession = CreateObject("Notes.NotesSession")
'Connect to the Lotus Notes database
Set NMailDB = NSession.GetDatabase("", "C:\Users\" & Environ("Username") & "\AppData\Local\IBM\Notes\Data\mail\" & Environ("Username") & ".nsf") 'Default server en database
If Not NMailDB.IsOpen Then
NMailDB.OpenMail
End If
'Loop through all views and print .Name tot Immediate Window
' Dim Map As Variant
' Dim Mappen As Object
' Set Mappen = NMailDB.Views
'
' For Each Map In Mappen
' Debug.Print Map.Name
' Next Map
'
End Sub
Easier than going through all views is to just go to one view that shows all documents. If it is a mail database, then the view is called "($All)"
Set allDocsView = NMailDB.getView("($All)")
allDocsView.autoUpdate = false
You can then loop through the documents in the view using
Set docToProcess = allDocsView.GetFirstDocument
While Not ( docToProcess Is Nothing )
'Do what you plan to do here
Set docToProcess = allDocsView.GetNextDocument( docToProcess )
Wend
UPDATE:
As you want to loop through Folders, not views, you need to do something like the following
Dim sess As New notessession
Dim db As NotesDatabase
Dim views As Variant
Set db = sess.CurrentDatabase
views = db.Views
Forall v In views
If v.isFolder Then ' Needed so that we are only processing Folder objects and not views - you will need to check that you are not processing system folders e.g. $Inbox etc
'Do your processing of documents here
End If
End Forall
Why is following code running from MS Word (MailMerge main document) freezing the application on ThisDocument.Close False?
Do I need to close the Scripting.Dictionary in some way other than setting the object to nothing?
There is only one instance of Word active, it is visible, ThisDocument is not the active document.
I am even explicitly activating the last opened document, even if it is already active. Not sure if I even need to set the oWorkbook and oExcel to nothing.
Sub MailMergeAlternative()
Dim oExcel As Object
Dim oWorkbook As Object
Dim oFirstCell As Object
Set oExcel = CreateObject("Excel.Application")
Set oWorkbook = oExcel.workbooks.Open(SOUBOR)
Set oFirstCell = oWorkbook.sheets(SESIT).Cells(1, 1)
Dim Dict As Object
Set Dict = MakeDictionary() ' Scripting.dictionary
Dim oDoc As Object
Dim Radek As Long
Dim Radku As Long
Radku = oFirstCell.currentregion.Rows.Count
For Radek = 2 To Radku
' ... fill Dict, use MailMerge to create new document for active record ...
Set oDoc = ActiveDocument ' the new document after MailMerge
' ... insert values, save the new document, do not close it ...
Next
Closing:
oDoc.Activate ' <== set to active, not needed
Set Dict = Nothing
oWorkbook.Close
oExcel.Quit
Set oWorkbook = Nothing ' probably not needed, closed above
Set oExcel = Nothing ' probably not needed, closed above
ThisDocument.Close False ' <== Problem
End Sub
Expected:
The code runs, creates new document(s) and closes the document which is containing the macro and from where it was called. The last active document stays open (the newly created one), or if nothing was created, Word app closes.
What is happening:
The document closes, the last active document stays open. But Word freezes and the document needs to be found in Task Manager and "brought to foreground". This is not a problem when using MailMerge alone (with additional vba work) and seems to be connected to use of Excel and Scripting.Dictionary.
Since you don't provide a [mcve] so that we can test exactly what you're doing it's possible that the following solution won't work for your exact environment. My test was run on the code below, which essentially creates a number of new documents then closes a document. (I have no access to your Excel content or to MakeDictionary())
I created a template (dotm) and put the code in that, closed it, created a new document from the template. This document has access to the code, via its link to the template. Closing the document will also release the template (unless another document based on it is opened). But in my test the code finished without an error.
Sub TestCloseSelfDocument()
Dim docMmMainMerge As Word.Document
Set docMmMainMerge = ActiveDocument
Dim Dict As Object
Dim oDoc As Object
Dim Radek As Long
Dim Radku As Long
Radku = 5
For Radek = 2 To Radku
Documents.Add
' ... fill Dict, use MailMerge to create new document for active record ...
Set oDoc = ActiveDocument ' the new document after MailMerge
' ... insert values, save the new document, do not close it ...
Next
Closing:
Set Dict = Nothing
docMmMainMerge.Close False
End Sub
I'm trying to write a Excel VBA code which allows me to automatically create and send a Lotus Notes Email. The problem I face is the difficulty to create a rich text Email, so I think it would be easier to open a draft email, with a marker text which will be replaced (for exameple PASTE EXCEL CELLS HERE) and then just:
.GotoField ("Body")
.FINDSTRING "PASTE EXCEL CELLS HERE"'
and replace.
Any help on how to open a certain draft email? Perhabs something as .CreateDocument property?
Thank you very much!
Others have proposed interesting concepts, but the most robust approach would be to use HTML in a MIME enitity that is mapped to the Body Rich Text item. Using NotesSession..Convertmime = False you can build the body as HTML and then send the message. Based on the post by Joseph Hoetzl here, the LotusScript equivalent is this:
Sub Initialize()
Dim s As New NotesSession
Dim db As NotesDatabase
Dim stime as Single
Dim alog As New NotesLog("debug")
Call alog.OpenAgentLog()
stime = Timer
On Error GoTo eh
Dim doc As NotesDocument
Dim body As NotesMIMEEntity
Dim header As NotesMIMEHeader
Dim stream As NotesStream
Dim child As NotesMIMEEntity
Dim sendTo As String
Dim subject As String
s.Convertmime = False
sendto = s.Effectiveusername
subject = "Demo Message"
Set db= s.Currentdatabase
Set doc=db.Createdocument()
Set stream = s.CreateStream
Set body = doc.CreateMIMEEntity
Set header = body.CreateHeader({MIME-Version})
Call header.SetHeaderVal("1.0")
Set header = body.CreateHeader("Content-Type")
Call header.SetHeaderValAndParams({multipart/alternative;boundary="=NextPart_="})
'Add the to field
Set header = body.CreateHeader("To")
Call header.SetHeaderVal(SendTo)
'Add Subject Line
Set header = body.CreateHeader("Subject")
Call header.SetHeaderVal(subject)
'Add the body of the message
Set child = body.CreateChildEntity
Call stream.WriteText("<h1>Demo HTML Message</h1>")
Call stream.WriteText(|<table colspacing="0" colpadding="0" border="none">|)
Call stream.WriteText(|<tr><td>cell 1.1</td><td>cell 1.2</td><td>cell 1.3</td></tr>|)
Call stream.WriteText(|<tr><td>cell 2.1</td><td>cell 2.2</td><td>cell 2.3</td></tr>|)
Call stream.WriteText(|<tr><td>cell 3.1</td><td>cell 3.2</td><td>cell 3.3</td></tr>|)
Call stream.WriteText(|</table>|)
Call stream.WriteText(|<div class="headerlogo">|)
Call stream.WriteText(|<!-- ...some more HTML -->|)
Call child.setContentFromText(stream, {text/html;charset="iso-8859-1"}, ENC_NONE)
Call stream.Truncate 'Not sure if I need this
Call stream.Close
Call doc.CloseMIMEEntities(True)
Call doc.replaceItemValue("Form", "Memo")
Call doc.Send(False, sendTo)
es:
Exit Sub
eh:
Dim emsg$
emsg = Error & " at " & Erl & " in " & s.Currentagent.name
Call alog.logError(Err, emsg)
MsgBox "ERROR: " & Err & ": " & emsg
Resume es
End Sub
All of this should convert fairly easily to VBA in Excel. You can, of course be as complex as you want with your HTML.
The word "draft" is probably inappropriate here, but then again so is the word "template". Both have specific meanings in Lotus Notes that aren't what you really want. Users can delete drafts, and templates are an entirely different thing. So let's just call it a boilerplate message.
I would recomemnd creating a special mail database (NSF file) on the Domino server, which will just serve as a repository for your boilerplate. You can create a folder in that mail database called "Boilerplates". Using Domino Designer you can modify that folder's design so that the Subject column is the first column in the view, and it is sorted.
Once you have that done and you have created some boilerplates and saved them in the folder, you can use VBA to do a NotesSession.getDatabase call, NotesDatabase.getView call (this is used for folders as well as views), and then use NotesView.getDocumentByKey() to retrieve a specific boilerplate by the Subject you have assigned to it. Note that you do not have to copy this document to the user's mail database in order to mail it.
What you want to do is non-trivial, but you mention a draft email so there may be a workaround.
In your mail settings you can specify a signature file which can be an external html file on disk. So modify the signature file, then create your new mail which will then populate the body field the way you want it.
For sample code, within the memo form there should be a button to specify what signature file to use. You can use that as the baseline.
Rich text is not that hard to work with, but you need to look at the Domino Designer help, especially the classes NotesRichTextItem and NotesRichTextStyle. You also need to understand the DOM (Domino Object Model). Then you can create your mail content programatically.
Otherwise I think Richard's solution is the best, that you have a separate database where you get the rich text snippets, and use the AppendRTItem method of the NotesRichText class to put it into your email.
Thank you all guys!
But I found exactly what I wanted, without having to recreate the whole Email everytime:
Sub EditSelectedMail()
Dim NSession As Object
Dim NDatabase As Object
Dim NUIWorkspace As Object
Dim NUIdoc As Object
Set NSession = CreateObject("Notes.NotesSession")
Set NUIWorkspace = CreateObject("Notes.NotesUIWorkspace")
Set NDatabase = NSession.GetDatabase("", "")
If Not NDatabase.IsOpen Then NDatabase.OPENMAIL
Set NUIdoc = NUIWorkspace.EDITDOCUMENT(True)
With NUIdoc
'Find the marker text in the Body item
.GotoField ("Body")
.FINDSTRING "**PASTE EXCEL CELLS HERE**"
'Copy Excel cells to clipboard
Sheets("Sheet1").Range("A1:E6").Copy
'Create a temporary Word Document
Set WordApp = CreateObject("Word.Application")
WordApp.Visible = False
WordApp.Documents.Add
'Paste into Word document and copy to clipboard
With WordApp.Selection
.PasteSpecial DataType:=10
'Enum WdPasteDataType: 10 = HTML; 2 = Text; 1 = RTF
.WholeStory
.Copy
End With
'Paste from clipboard (Word) to Lotus Notes document
.Paste
Application.CutCopyMode = False
'WordApp.Quit SaveChanges:=False
Set WordApp = Nothing
End With
End Sub
I just select my "template", copy it into a new message, and then run the macro.
I have the code to send an email through Lotus Notes 7. It works well. From what I've seen there are two methods of doing this, and only one of them requires that you specify a database. I'm using the method that doesn't require that, because multiple people will be using this code, and most of them don't know how to modify or read VB.
What I want to do is set the reply-to portion of the email. I have tried every variation I can think of, and nothing seems to work (different errors for different ways).
Thanks in advance,
Aaron.
Sub Email_Atrack_Report(SubjectLine As String, _
AgentOracle As String, TMAddress As String)
Dim NSession As Object
Dim NUIWorkSpace As Object
Dim NDoc As Object
Dim NUIdoc As Object
Set NSession = CreateObject("Notes.NotesSession")
Set NUIWorkSpace = CreateObject("Notes.NotesUIWorkspace")
Set NDoc = NUIWorkSpace.ComposeDocument("", "", "Memo")
Set NUIdoc = NUIWorkSpace.CURRENTDOCUMENT
With NUIdoc
.FieldSetText "EnterSendTo", AgentOracle & "#Company.com"
.FieldSetText "EnterCopyTo", TMAddress
.FieldSetText "Subject", SubjectLine
.FieldSetText "Body", "**PASTE Atrack HERE**"
.GotoField ("Body")
.FINDSTRING "**PASTE Atrack HERE**"
Sheets("EmailOutput").Range("MessageBody").Copy
.Paste
.send
.Close
End With
Set NUIdoc = Nothing
Set NDoc = Nothing
Set NUIWorkSpace = Nothing
Set NSession = Nothing
End Sub
You can use the Principal field to specify an address that will show up as the "From" address. I don't believe there is a way to set this via NotesUIDocument, but you should be able to get the mail database using the NotesDatabase.OpenMail method.
Set session = CreateObject("Notes.NotesSession")
Set maildb = session.getDatabase("", "")
Call maildb.OpenMail
If Not maildb.IsOpen Then Call maildb.Open("", "")
Set maildoc = maildb.createdocument
Set body = maildoc.createrichtextitem("body")
Call body.AppendText( Sheets("EmailOutput").Range("MessageBody").Text )
Call maildoc.replaceitemvalue("form", "memo")
Call maildoc.replaceitemvalue("subject", subject)
Call maildoc.replaceitemvalue("principal", "reply-to-this-user")
Call maildoc.send(false,recipient)
There a two ways to solve this, building the document and use the send method, or copy the document to the mail.box.
A good way to start is to read this blog entry by Jake Howlett
These are the items that can be used in the email:
Principal
iNetFrom
DisplaySent
ErrorsTo
ReplyTo
CopyTo
BlindCopyTo
SendTo
You should just need to set the "ReplyTo" item on the document, as in:
.FieldSetText "ReplyTo", "address#company.com"