Email displays but does not send - excel

I am testing out sending emails from Excel using VBA.
I do not get an email sent to my inbox.
The code is below:
Sub email_from_excel()
Dim emailApplication As Object
Dim emailItem As Object
Set emailApplication = CreateObject("Outlook.Application")
Set emailItem = emailApplication.CreateItem(0)
'Now build the email
emailItem.to = "emailaddress#test.com"
emailItem.Subject = "This is a test y'all."
emailItem.Body = "This is a test message ya'll."
'Send the email
emailItem.Send
End Sub
In line 6 of the code, I put my email address in between the quotation marks.
I enabled Microsoft Outlook under Tools - References in VBA. No error comes up, but no email gets sent.
I commented out the emailItem.Send and added in emailItem.Display ran the code and an email showed.

Keep in mind that message submission is an asynchronous process. You need to wait for the message to go out before releasing (and thus closing) Outlook.
As a test, start Outlook before your code runs - this way it will stay open even after your code is finished executing.

I've been through the same problem, what seems to be happening is the Excel deletes outlook from memory before sending the message,
Before the solution here comes a tip, instead of using create object you can declare the variable as application.outlook and application.mailitem
It makes all the methods and propertys appears as hint while you type
Well, I solved it by declaring a global variable to store outlook.application
Global appOutlook as application.outlook
Then in "this workbook" inside the open event I set the variable
Set appOutlook = new application.outlook
Now within the macro that send the e-mail you declare an set the variable to store de email
Dim eMail as Outlook.mailitem
Set eMail = appOutlook.CreateItem(olMailitem)
Also you can improve your code by using with statement
With eMail
.to
.body
End with
Instead of type the car name every time u can use with and then you just need to type a dot and access the methods and propertys
Now the last part is to set eMail to nothing
Set eMail = nothing
I don't know why this is necessary, but my codes usually don't send the e-mail without it
Well this should make it works, you can use a local variable, but if you need to send more than one email in a short time, then any one you go, they will be in some kind of "void" and you go when you run a code that actually works, by using a global variable to store the application, it starts and only stops if you code it, the application crashes or closes, well sorry for the big text, and i hope to help

Related

HypRetrieve not retrieving correct status code

Background
I have two databases that I need to connect to. One is in Hyperion and the other one is in ESS. I have imported the smartview.bas as stated by the documentation and I am attempting to use the functions within it. I have dummy sheets (SavedLogHyperion and SavedLogESS) for each enviroment to make sure the users logs in before running all the code. I want to retrieve the proper error code if the user closes the window without logging or other things that may prevent the successful login.
Problem
The HypRetrieve only acknowledge for the first result: if the user was able to log to Hyperion environment, but if ESS login window is cancelled or provided with non-valid credentials and then closed, it detects the code as 0 ("Ok"), thus detecting a successful login for the second environment when it was not.
Code
I wrote a function to retrieve the number, I thought that it could be a time thing and that is why I made it (so for the main code could resolve on time), but it seems like it is not.
Function Return_NumCodeSVHypRetrieve(VarTxtSheetToLogin As Variant) As Long
Dim NumCodeHypRetrieve As Long
NumCodeHypRetrieve = HypRetrieve(VarTxtSheetToLogin)
Return_NumCodeSVHypRetrieve = NumCodeHypRetrieve
End Function
This function is called in my main sub
Sub Main()
Dim NumCodeConnectionSheet1 As Long
Dim NumCodeConnectionSheet2 As Long
NumCodeConnectionSheet1 = Return_NumCodeSVHypRetrieve("SavedLogHyperion")
NumCodeConnectionSheet2 = Return_NumCodeSVHypRetrieve("SavedLogESS") 'If I log in "SavedLogHyperion", this variable becomes 0 too, or any other error code that variable had
End Sub
Question
How can I make the correct code according to the sheet attempted to log be correctly saved? I am clueless on what may be the approach
Solution:
The problem seems to be on how the function works; I noticed that when the function is applied, it activates the sheet, which lead me to believe that there was a problem on timing events, I came with the following solution, which has been basically to provide the scenario that I saw the function is expecting to, also I noticed that if I set the NumCode to retrieve as long as the direct result, it does not behave as expected, my approach was to declare it a variant and then cast it to a long instead.
Function Return_NumCodeSVHypRetrieve(VarTxtSheetToLogin As Variant) As Long
Dim VarNumCode As Variant
'It seems the function relies on the sheet being activated and if the Retrives does it, it takes miliseconds to do, which are not sync with excel life cycle, thus causing missreadings
Sheets(VarTxtSheetToLogin).Visible = True: Sheets(VarTxtSheetToLogin).Select: DoEvents
VarNumCode = HypRetrieve(VarTxtSheetToLogin)
Sheets(VarTxtSheetToLogin).Visible = False
Return_NumCodeSVHypRetrieve = CLng(VarNumCode)
End Function

VBA issues with sending SMS

I have a code for my Excel application. It generates a product invoice and every time the invoice generated it will send the current billed amount along with thanks message. I have purchased a bulk SMS account and they have provided me the API.
I am using the "ActiveWorkbook.FollowHyperlink" method to send SMS, but it is sending SMS 2 times. Can anyone tell me why this method sends sms 2 times??
I have written the following program:
Sub Macro1()
Dim murl As String
murl = "<< SMS API HERE >>"
ActiveWorkbook.FollowHyperlink Address:=murl
End Sub
Consider using a raw GET request to your API, here is an example using late-binding to send a GET request to a google page - the MsgBox line is simply showing the response from google and you can replace the google.co.uk URL with your own API URL.
Public Sub Send_GET()
Dim con As Object ' MSXML2.ServerXMLHTTP60
Set con = CreateObject("MSXML2.ServerXMLHTTP") ' New MSXML2.ServerXMLHTTP60
con.Open "GET", "https://www.google.co.uk", False
con.setRequestHeader "Content-type", "application/x-www-form-urlencoded"
con.send
MsgBox con.responsetext
End Sub
I've used late binding but if you want to explore the proper objects and properties then add a reference to "Microsoft XML v6.0" in your VBA project and you can get rid of the Object and CreateObject parts - sending requests like this is SO USEFUL.
Don't forget to mark an answer as correct if it helps solve your problem.

How to make Toaster Notification on Excel with VBA

I would like to create/use toasters notifications on Excel. Because we already use MsgBox to notify the user that something happen.
But it make the script to stop (pause).
Have you any idea of how to do ?
On google there is "System Tray Notification" but it need a lot of code and this is a old method. Can't find if there is a new method.
For example, the plugin from SAP : "Analysis For Office" put notifications on Excel.
I looked into this once and almost gave up on it entirely until I found a rather 'cheaty' way of alerting users of info without suspending execution, that works on my users machines.
We run Windows 10 here and have SCCM installed for software distribution and updates. I've absolutely no idea if that's mandatory in Windows for updates or not, so I've no idea if this works for you.. but the following code works a treat here if you don't mind the notification resembling a Software Centre notification:
Sub Toastnote(ccmTitle, ccmText)
Shell "c:\windows\ccm\sctoastnotification.exe """ & ccmTitle & """ """ & ccmText & """ "
End Sub
You can call it with:
toastnote "title goes here","message goes here"
It creates a little pop-up that looks like this:
As I say, it's a bit of a cheat and might confuse users who regularly receive CCM notifications, but for my user-base that wasn't an issue.
Lastly, it's probably worth wrapping this in an IF statement that checks the .exe file exists - just a thought..
Using the Plugin "Analysis For Office" from SAP, you can define messages and add them to the standard SAP-AnalysisForOffice message dialog :
Dim lResult As Long
lResult= Application.Run("SAPAddMessage", "This is a new error message!", "ERROR")
The message 'This is a new error message' with severity Error is displayed in the message dialog.
It will do the same as the picture sent with my question.
Source
Details about SAPAddMessage
I had a similar requirement (mainly for debugging)
My solution was to pop up a small form with a single label control and unload it 4 seconds later. The form proeprties are set no not show modal etc.
in a VBA "Module"
Private mFrmToast As frmToast
Public Sub clearToast()
On Error Resume Next
If Not mFrmToast Is Nothing Then
mFrmToast.Hide
Unload mFrmToast
Set mFrmToast = Nothing
End If
End Sub
Public Sub showToast(message As String)
On Error GoTo er_clear_in_4
If mFrmToast Is Nothing Then
Set mFrmToast = New frmToast
End If
mFrmToast.message = message
If Not mFrmToast.Visible Then
Call mFrmToast.Show(False)
End If
er_clear_in_4:
Application.OnTime Now + TimeValue("00:00:04"), "clearToast"
End Sub
The form "code behind" module contained a sample write only property, "message".
Option Explicit
Public Property Let message(ByVal sMessage As String)
lblMessage.Caption = sMessage
End Property
The usage is simply
showToast("your message here")

Force a COM server to remain open

I have a COM automation server hosted by a VB6 exe.
The COM API is used from Excel VBA:
Dim o as MyCOMAPI.MyCOMType
Set o = new MyCOMAPI.MyCOMType
o.DoSomething
When I create objects in VBA the exe is started along with COM automation and VBA can use the API.
But the exe is closed quickly and "randomly" by Excel, I guess when Excel decides it doesn't need the COM API anymore.
This behaviour is causing random errors.
The simple solution is to start the exe before running the VBA code ; in this case all is working fine as the exe won't stop running until closed by the user.
Have you some information/documentation about the way Excel VBA manages calls to hosted APIs?
Is there a way to avoid this behaviour and have the exe kept open until the VBA code decides to stop it?
This would be the default behavior for a COM automation server when the last object is dereferenced, meaning that the variable that points to the server is set to nothing.
Now, if your code looks something like this today:
Sub MyFunction()
...
Dim o as MyCOMAPI.MyCOMType
Set o = new MyCOMAPI.MyCOMType
o.DoSomething
End Sub
Then, the server life is connected to the life of the o variable. That variable gets set to nothing when the function is finished, and then the server will be shut down (unless there are other variables keeping it alive).
To make sure that your COM server is kept alive for a longer time, simply define the variable as a Public variable as in the sample below.
This sample will start and show Excel and keep it open until the ShutdownExcel function is called.
Public o As Excel.Application
Sub MakeSureExcelIsRunning()
If o Is Nothing Then
Set o = New Excel.Application
o.Visible = True
End If
End Sub
Sub ShutdownExcel()
Set o = Nothing
End Sub
From COM docs.
**Component Automation**
Shutting Down Objects
ActiveX objects must shut down in the following way:
If the object's application is visible, the object should shut down only in response to an explicit user command (for example, clicking Exit on the File menu) or the equivalent command from an ActiveX client.
If the object's application is not visible, the object should shut down only when the last external reference is gone.
If the object's application is visible and is controlled by an ActiveX client, it should become invisible when the user shuts it down (for example, clicking Exit on the File menu). This behavior allows the controller to continue to control the object. The controller should shut down only when the last external reference to the object has disappeared.
© Microsoft Corporation. All rights reserved.
When you write an COM server exe the first thing you do it take a reference to yourself when starting as a normal exe else the exe shuts down as soon as initialisation is over.

CreateObject randomly throws "A system shutdown has already been scheduled" error

I googled and SO'd, and nothing.
My job revolves around making my co-workers lives easier.
Currently, they are using very clunky spreadsheets designed 10+ years ago.
In the process of migrating their tools and reports to the local intranet using PHP, i have configured a spreadsheet that downloads that persons permissions based on their Application.Username
Then a little back and forth with the server to generate a session key, and then pop internet explorer opens up with the relevant tool they selected from a dropdown within the workbook - meaning their session and tools are then purely browser based.
All works great, however randomly, sometimes, when the sub to open the internet browser is triggered a very bizarre error message appears :-
Upon clicking Debug, the following function is shown, and you can see for yourself which line is highlighted in yellow.
I can confirm i do not have any tasks at all within my taskschedule. When i end this, and run it again, chances are it runs just fine.. it is just sometimes that this error pops up.
Please help! Thank in advance.
With errors this seemingly-unrelated and intermittent, I usually opt for either a bit of delay, catching the error and retrying or both.
Try the following (retry without a delay):
Function gogogo(sessKey)
On Error GoTo ErrHandler
reportId = Sheet2.Range("A" & (Sheet2.Range("B1").Value + 1)).Value
Set objIE = CreateObject("InternetExplorer.Application")
URL = "http://localinternetdomainhere/OnlineTools/" & reportId & "/access/" & sessKey
With objIE
.Visible = True
.navigate URL
End With
ThisWorkbook.Saved = True
ThisWorkbook.Close False
Exit Function
ErrHandler:
If Err.Number = &H800704A6 Then 'Put a breakpoint here to make sure this is the ACTUAL VBA error number and not the ActiveX one. You might need to check against the Err.LastDllError property
Resume
End If
Err.Raise Err.Number, Err.Source, Err.Description,err.HelpFile, err.HelpContext 'Reraise the error otherwise
End Function

Resources