How can I send a mail using MAPI with an HTML body? I need to create table in a message body.
I'm using vb6 and the MAPI control. Any ideas?
Function MailSend(sSendTo As String, sSubject As String, sText As String) As Boolean
On Error GoTo ErrHandler
With MAPISession1
If .SessionID = 0 Then
.DownLoadMail = False
.LogonUI = True
.SignOn
.NewSession = True
MAPIMessages1.SessionID = .SessionID
End If
End With
With MAPIMessages1
.Compose
.RecipAddress = sSendTo
.AddressResolveUI = True
.ResolveName
.MsgSubject = sSubject
.MsgNoteText = sText
.Send False
End With
MailSend = True
Exit Function
ErrHandler:
'MsgBox Err.Description
MailSend = False
End Function
MAPI control uses Simple MAPI, which does not handle HTML. There is a trick when using Simple MAPI directly (MAPISendMail) - set the body to NULL and attach and HTML file: it will be used as the message body. I don't know if that trick will work with the MAPI control.
Why not switch to using the Outlook Object Model? It is perfectly capable of handling HTML:
set App = CreateObject("Outlook.Application")
set NS = App.GetNmaespace("MAPI")
NS.Logon
set Msg = App.CreateItem(0)
Msg.To = sSendTo
Msg.Subject = sSubject
Msg.HTMLBody = sYourHTMLBody
Msg.Send 'or Msg.Display
keep
.MsgNoteText ="";
.AttachmentPathName = result
ie.
With MAPIMessages1
.Compose
.RecipAddress = sSendTo
.AddressResolveUI = True
.ResolveName
.MsgSubject = sSubject
.MsgNoteText =""
.AttachmentPathName = "c:\yourHtml.html"
.Send False
End With
Related
I'm currently working on an excel table that reads various API's and processes the results.
I'm trying to adapt an api request for this table, but unfortunately I can't do it.
I'm assuming this good working code:
Public Sub Main()
On Error Resume Next
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", "https://api.binance.com/api/v3/ticker/price", False
On Error Resume Next
http.Send
On Error GoTo error
Set json = ParseJson(http.ResponseText)
i = 10
For Each Item In json
If Item("symbol") = Workbooks(1).Worksheets("Tabelle1").Range("A1").Value And Workbooks(1).Worksheets("Tabelle1").Range("A1").Value <> "" Then
Sheets(1).Cells(1, i).Value = Item("price")
i = i + 1
End If
Next
Exit Sub
error:
End Sub
CELL A1 says: ETHBTC and I get the corresponding value in J1
Unfortunately, the following code doesn't work and I don't understand why:
Sub GetVolume()
On Error Resume Next
'List of all symbols
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", "https://api.coincap.io/v2/candles", False
On Error Resume Next
http.Send
Set json = ParseJson(http.ResponseText)
i = 10
For Each Item In json("data")
If Item("exchange") = Workbooks(1).Worksheets("Tabelle1").Range("A1").Value And Workbooks(1).Worksheets("Tabelle1").Range("A1").Value <> "" Then
Sheets(1).Cells(1, i).Value = Item("volume")
i = i + 1
End If
Next
Exit Sub
error:
End Sub
In this case, the content of cell A1 looks like this:
binance&interval=m5&baseId=monero"eId=bitcoin&start=1649894400000&end=1649898000000
The request for this looks like this:
https://api.coincap.io/v2/candles?exchange=poloniex&interval=h1&baseId=ethereum"eId=bitcoin&start=1649894400000&end=1649898000000
I would be very grateful for a tip
I've tried different combinations, but get no answer
"https://api.coincap.io/v2/candles" HTTPRequest.responseText:
"{"error":"missing quote","timestamp":1672666785053}"
The code is returning an missing quote error, caused by missing query parameters.
CoinCap Docs has a query builder that you can use. Start with a working query and than start modifying parameters until it fits your specifications.
I recommend creating a function to handle returning the json data. This simplifies development by making it easier to test the code.
Function QueryCoinCap(URL As String) As Object
On Error GoTo QueryCoinCap_Error
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", URL, False
.Send
Set QueryCoinCap = ParseJson(.ResponseText)
End With
On Error GoTo 0
Exit Function
QueryCoinCap_Error:
Rem CoinCap was unable to process the request
Rem to simplify the error handle I'll create a Scripting.Dictionary and ADD A CUSTOM ERROR TO IT
Rem This allows us to treat all errors in the same way
Dim Dictionary As Object
Set Dictionary = CreateObject("Scripting.Dictionary")
Dictionary("error") = "CoinCap was unable to process the request"
Set QueryCoinCap = Dictionary
End Function
Sub WorkingExampleQueryCoinCap()
Dim URL As String
URL = "https://api.coincap.io/v2/assets"
Dim JsonDictionary As Object
Set JsonDictionary = QueryCoinCap(URL)
If JsonDictionary.Exists("error") Then
Debug.Print JsonDictionary("error")
Else
Stop
Rem Do Something
End If
End Sub
Sub ErrorExampleQueryCoinCap()
Dim URL As String
URL = "https://api.coincap.io/v2/candles"
Dim JsonDictionary As Object
Set JsonDictionary = QueryCoinCap(URL)
If JsonDictionary.Exists("error") Then
Debug.Print JsonDictionary("error")
Else
Rem Do Something
End If
End Sub
I'm a beginner with VBA and coding in general and I'm stuck with a problem with my VBA code. Here's what I want to do :
I have two fillable fields (f_autpar_nom and f_autpar_fiche) with my Access database who need to be on my Word file at two formfield (eleves_nom and eleves_numfiche) with a command_click(). Then, my Word document opens and prompts me with a "do you want to save this" and then the Word document save as a PDF and is sent by email.
Everything is working except one thing : The formfields aren't updated when I print the PDF and return the default message I set (which is "erreur").
What I need is to find a way to update the formfield before my messagebox prompt me to send the email.
Here's the code I have with Access
Function fillwordform()
Dim appword As Word.Application
Dim doc As Word.Document
Dim Path As String
On Error Resume Next
Error.Clear
Path = "P:\Commun\SECTEUR DU TRANSPORT SCOLAIRE\Harnais\Autorisations Parentales\Autorisation parentale vierge envoyée\Autorisation_blank.docm"
Set appword = GetObject(, "word.application")
If Err.Number <> 0 Then
Set appword = New Word.Application
appword.Visible = True
End If
Set doc = appword.Documents.Open(Path, , False)
With doc
.FormFields("eleves_nom").Result = Me.f_autpar_nom
.FormFields("eleves_numfiche").Result = Me.f_autpar_fiche
appword.Visible = True
appword.Activate
End With
Set doc = Nothing
Set appword = Nothing
End Function
Private Sub Commande47_Click()
Dim mydoc As String
mydoc = "P:\Commun\SECTEUR DU TRANSPORT SCOLAIRE\Harnais\Autorisations Parentales\Autorisation_blank.docm"
Call fillwordform
End Sub
and with Word
Private Sub document_open()
Dim outl As Object
Dim Mail As Object
Dim Msg, Style, Title, Help, Ctxt, Response, MyString
Dim PDFname As String
Msg = "L'autorisation sera sauvegardée et envoyée par email. Continuer?"
Style = vbOKCancel + vbQuestion + vbDefaultButton2
Title = "Document"
Ctxt = 1000
Response = MsgBox(Msg, Style, Title, Help, Ctxt)
If Response = vbOK Then
ActiveDocument.Save
PDFname = ActiveDocument.Path & "\" & "Autorisation Parentale " & FormFields("eleves_nom").Result & ".pdf"
ActiveDocument.SaveAs2 FileName:=PDFname, FileFormat:=wdFormatPDF
Set outl = CreateObject("Outlook.Application")
Set Mail = outl.CreateItem(0)
Mail.Subject = "Autorisation parentale " & FormFields("eleves_nom").Result & " " & FormFields("eleves_numfiche")
Mail.To = ""
Mail.Attachments.Add PDFname
Mail.Display
Application.Quit SaveChanges:=wdDoNotSaveChanges
Else
MsgBox "Le fichier ne sera pas envoyé."
Cancel = True
End If
End Sub
I didn't mean to remove the Set Doc = Nothing. My intention was to point out that whatever changes you made before that command must be lost because they weren't saved. In the code below the document is closed and saved.
Private Sub Commande47_Click()
Dim mydoc As String
mydoc = "P:\Commun\SECTEUR DU TRANSPORT SCOLAIRE\Harnais\Autorisations Parentales\Autorisation_blank.docm"
Call FillWordForm
End Sub
Function FillWordForm(Ffn As String)
Dim appWord As Word.Application
Dim Doc As Word.Document
On Error Resume Next
Set appWord = GetObject(, "word.application")
If Err.Number Then Set appWord = New Word.Application
appWord.Visible = True
On Error GoTo 0
Set Doc = appWord.Documents.Open(Ffn, , False)
' the newly opened document is activated by default
With Doc
.FormFields("eleves_nom").Result = Me.f_autpar_nom
.FormFields("eleves_numfiche").Result = Me.f_autpar_fiche
.Close True ' close the file and save the changes made
End With
Set appWord = Nothing
End Function
However, I also agree with #Kazimierz Jawor that your construct is unfortunate. Basically, the document's On_Open procedure should run when you open the document from Access. Therefore the email is probably sent before you even get to setting the form fields. My suggestion to save the changes is likely to take effect only when you run the code the second time.
The better way should be to send the mail from either Access or Word. My preference would be the latter. It should be easy to extract two values from an Access table using Word, add them to a Word document and mail out the whole thing. I don't see, however, why you should use the Open event to do that. If that choice is the more logical one then doing everything from within Access would be the conclusion.
The below code is part of a program that populates a word document from an access database.
This part of the code adds a picture with the user's signature at the bookmark location 'Signature'. For some reason it works the first attempt, but the nex time it runs it pastes at the initial document's bookmark location and not the new document.
appword.ActiveDocument.Bookmarks("Signature").Select
Selection.Find.ClearFormatting
With Selection.Find
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.InlineShapes.AddPicture FileName:= _
SASignaturePath, _
LinkToFile:=False, SaveWithDocument:=True
I've attempted to use a few other selection commands like:
Selection.Goto What:=wdGoToBookmark, Name:="Signature"
and
objWork.ActiveDocument.Bookmarks("Signature").Range.Select
with no luck.
Edit: Adding additional info as requested.
The entire function pulls some global variables from access and autopopulates a word document with them. The global variable 'SASignaturePath' has the file location of the signature image.
Below is the entire function being called when the user presses the 'create cost letter' button.
Function fillCostLetter()
Dim appword As Word.Application
Dim doc As Word.Document
Dim Path As String
TodayDate = Format(Now(), "mmmm dd, yyyy")
On Error Resume Next
Error.Clear
Set appword = GetObject(, "word.application")
If Err.Number <> 0 Then
Set appword = New Word.Application
appword.Visible = True
End If
Path = "Z:\DocFolder\ServiceAssociateToolBox\CostLetterTestStage.docx"
Set doc = appword.Documents.Open(Path, , True)
With doc
.FormFields("Date").Result = TodayDate
.FormFields("BillName").Result = BillName
.FormFields("BillAmmount").Result = BillAmmount
.FormFields("BillAddress").Result = BillAddress
.FormFields("BillAmmount").Result = BillAmmount
.FormFields("BillCity").Result = BillCity
.FormFields("BillState").Result = BillState
.FormFields("BillZip").Result = BillZip
.FormFields("SiteZip").Result = SiteZip
.FormFields("SiteState").Result = SiteState
.FormFields("SiteCity").Result = SiteCity
.FormFields("SiteStreetType").Result = SiteStreetType
.FormFields("SiteStreetName").Result = SiteStreetName
.FormFields("SiteStreetNo").Result = SiteStreetNo
.FormFields("BillName2").Result = BillName
.FormFields("WorkRequest").Result = WR_NO
.FormFields("CustName").Result = CustName
.FormFields("SAName").Result = SAName
.FormFields("SADeptartment").Result = SADept
.FormFields("SAPhone").Result = SAPhone
Selection.Find.ClearFormatting
With Selection.Find
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
ActiveDocument.Bookmarks("Signature").Range.InlineShapes.AddPicture FileName:= _
SASignaturePath, _
LinkToFile:=False, SaveWithDocument:=True
Selection.Goto What:=wdGoToLine, Which:=wdGoToAbsolute, Count:=1
End With
appword.Visible = True
appword.Activate
Set doc = Nothing
Set appword = Nothing
End Function
Changing and then using the selection as an insertion point is generally bad practice. What you should rather do is use the actual Range of the bookmark, which can be obtained by calling:
ActiveDocument.Bookmarks("BookmarkName").Range
The obtained Range can then be used in your above code instead of Selection, i.e.
ActiveDocument.Bookmarks("BookmarkName").Range.InlineShapes.AddPicture (...)
I've wrote a script to create a HTML file based on a SQL Query.... It has become necessary to have that HTML be emailed. Most of our execs use blackberry's and I want to send the HTML file as the body. I have found a round about way to get this done, by adding a WebBrowser, and having the web browser then load the file, and then using the below code to send. The problem i'm facing is if I automate the code fully, it will only email part of the HTML document, now if I add a button, and make it do the email function, it sends correctly. I have added a wait function in several different location, thinking it may be an issue with the HTML not being fully created before emailing. I have to get this 100% automated. Is there a way I can use the .HTMLBody to link to the actual HTML file stored on the C:(actual path is C:\Turnover.html). Thanks all for any help.
Public Sub Email()
Dim strdate
Dim iCfg As Object
Dim iMsg As Object
strdate = Date.Today.TimeOfDay
iCfg = CreateObject("CDO.Configuration")
iMsg = CreateObject("CDO.Message")
With iCfg.Fields
.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 1
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "xxxxx.com"
.Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1
.Item("http://schemas.microsoft.com/cdo/configuration/sendemailaddress") = """Turnover Report"" <TurnoverReports#xxxxx.com>"
.Update()
End With
With iMsg
.Configuration = iCfg
.Subject = "Turnover Report"
.To = "xxxxx#xxxxx.com"
'.Cc = ""
.HTMLBody = WebBrowserReportView.DocumentText
.Send()
End With
iMsg = Nothing
iCfg = Nothing
End Sub
used the below function to read in a local html file. then set
TextBox2.Text = getHTML("C:\Turnover2.html")
and also
.HTMLBody = TextBox2.Text
Private Function getHTML(ByVal address As String) As String
Dim rt As String = ""
Dim wRequest As WebRequest
Dim wResponse As WebResponse
Dim SR As StreamReader
wrequest = WebRequest.Create(address)
wResponse = wrequest.GetResponse
SR = New StreamReader(wResponse.GetResponseStream)
rt = SR.ReadToEnd
SR.Close()
Return rt
End Function
Right I'm trying to send an Email form an excel spreadsheet though lotus notes, it has an attachment and the body needs to be in HTML.
I've got some code that from all I've read should allow me to do this however it doesn't.
Without the HTML body the attachment will send, when I impliment a HTML body the Email still sends but the attachment dissapears, I've tried rearanging the order of the code cutting out bits that might not be needed but all is invain.
(You need to reference Lotus Domino Objects to run this code.
strEmail is the email addresses
strAttach is the string location of the attachment
strSubject is the subject text
strBody is the body text
)
Sub Send_Lotus_Email(strEmail, strAttach, strSubject, strBody)
Dim noSession As Object, noDatabase As Object, noDocument As Object
Dim obAttachment As Object, EmbedObject As Object
Const EMBED_ATTACHMENT As Long = 1454
Set noSession = CreateObject("Notes.NotesSession")
Set noDatabase = noSession.GETDATABASE("", "")
'If Lotus Notes is not open then open the mail-part of it.
If noDatabase.IsOpen = False Then noDatabase.OPENMAIL
'Create the e-mail and the attachment.
Set noDocument = noDatabase.CreateDocument
Set obAttachment = noDocument.CreateRichTextItem("strAttach")
Set EmbedObject = obAttachment.EmbedObject(EMBED_ATTACHMENT, "", strAttach)
'Add values to the created e-mail main properties.
With noDocument
.Form = "Memo"
.SendTo = strEmail
'.Body = strBody ' Where to send the body if HTML body isn't used.
.Subject = strSubject
.SaveMessageOnSend = True
End With
noSession.ConvertMIME = False
Set Body = noDocument.CreateMIMEEntity("Body") ' MIMEEntity to support HTML
Set stream = noSession.CreateStream
Call stream.WriteText(strBody) ' Write the body text to the stream
Call Body.SetContentFromText(stream, "text/html;charset=iso-8859-1", ENC_IDENTITY_8BIT)
noSession.ConvertMIME = True
'Send the e-mail.
With noDocument
.PostedDate = Now()
.Send 0, strEmail
End With
'Release objects from the memory.
Set EmbedObject = Nothing
Set obAttachment = Nothing
Set noDocument = Nothing
Set noDatabase = Nothing
Set noSession = Nothing
End Sub
If somone could point me in the right direction I'd be greatly appreciated.
Edit:
I've done a little more investigating and I've found an oddity, if i look at the sent folder the emails all have the paperclip icon of having an attachment even though when you go into the email even in the sent the HTML ones don't show an attachment.
I have managed to solve my own problem.
In teh same way you create a MIME entry and stream in the HTML you need to do the same with the attachment, you also need to put them both inside a MIME entry within the email itself to hold both the HTML and Attachment at the same level otherwise you end up with a situation of the email with the body and a child entry of the attachment which is within another attachment. (it's odd but true)
Thus this is my solution:
Sub Send_Lotus_Email(Addresses, Attach, strSubject, strBody)
'Declare Variables
Dim s As Object
Dim db As Object
Dim body As Object
Dim bodyChild As Object
Dim header As Object
Dim stream As Object
Dim host As String
Dim message As Object
' Notes variables
Set s = CreateObject("Notes.NotesSession")
Set db = s.CurrentDatabase
Set stream = s.CreateStream
' Turn off auto conversion to rtf
s.ConvertMIME = False
' Create message
Set message = db.CreateDocument
message.Form = "memo"
message.Subject = strSubject
message.SendTo = Addresses
message.SaveMessageOnSend = True
' Create the body to hold HTML and attachment
Set body = message.CreateMIMEEntity
'Child mime entity which is going to contain the HTML which we put in the stream
Set bodyChild = body.CreateChildEntity()
Call stream.WriteText(strBody)
Call bodyChild.SetContentFromText(stream, "text/html;charset=iso-8859-1", ENC_NONE)
Call stream.Close
Call stream.Truncate
' This will run though an array of attachment paths and add them to the email
For i = 0 To UBound(Attach)
strAttach = Attach(i)
If Len(strAttach) > 0 And Len(Dir(strAttach)) > 0 Then
' Get the attachment file name
pos = InStrRev(strAttach, "\")
Filename = Right(strAttach, Len(strAttach) - pos)
'A new child mime entity to hold a file attachment
Set bodyChild = body.CreateChildEntity()
Set header = bodyChild.CreateHeader("Content-Type")
Call header.SetHeaderVal("multipart/mixed")
Set header = bodyChild.CreateHeader("Content-Disposition")
Call header.SetHeaderVal("attachment; filename=" & Filename)
Set header = bodyChild.CreateHeader("Content-ID")
Call header.SetHeaderVal(Filename)
Set stream = s.CreateStream()
If Not stream.Open(strAttach, "binary") Then
MsgBox "Open failed"
End If
If stream.Bytes = 0 Then
MsgBox "File has no content"
End If
Call bodyChild.SetContentFromBytes(stream, "application/msexcel", ENC_IDENTITY_BINARY)' All my attachments are excel this would need changing depensding on your attachments.
End If
Next
'Send the email
Call message.Send(False)
s.ConvertMIME = True ' Restore conversion
End Sub
Here is my actual code. I'm not even using strong type.
Dim mobjNotesSession As Object ' Back-end session reference'
Dim bConvertMime As Boolean
Dim stream As Object
Dim mimeHtmlPart As Object
Const ENC_QUOTED_PRINTABLE = 1726
mobjNotesSession = CreateObject("Lotus.NotesSession")
mobjNotesSession.Initialize()
mobjNotesDatabase = mobjNotesSession.GetDatabase("HQ2", "tim4")
mobjNotesDocument = mobjNotesDatabase.CreateDocument
bConvertMime = mobjNotesSession.ConvertMime
mobjNotesSession.ConvertMime = False
stream = mobjNotesSession.CreateStream()
Call stream.WriteText(txtBody.Text)
mobjNotesBody = mobjNotesDocument.CreateMIMEEntity("Body")
mimeHtmlPart = mobjNotesBody.CreateChildEntity() 'This returns "Type Mismatch" error'
Call mimeHtmlPart.SetContentFromText(stream, "text/html; charset=""iso-8859-1""", ENC_QUOTED_PRINTABLE)
Call stream.Close()
mobjNotesSession.ConvertMime = bConvertMime
Call mobjNotesDocument.CloseMIMEEntities(True, "Body")
No sorry I didn't i was running this in VBA which isn't strong typed so i can get away with not knowing the actual variable type for the body identity. i 've not been able to test this but I belive you need to reset the declarations to
Dim bodyChild As NotesMIMEEntity
this is the one you have trouble with the ones bellow you may find cause problems as well
Dim s As New NotesSession
Dim db As NotesDatabase
Dim body As NotesMIMEEntity
Dim header As NotesMIMEHeader
Dim stream As NotesStream
Dim host As String
Dim message As NotesDocument
Hope this helps