Outlook code stopped working - vba

I have a 1-min delay on all emails and want to assign a category set up as an exception to the rule to send immediately.
I created the macro but it stopped working.
Public Sub CategoriesButton()
Dim Item As Outlook.MailItem
Set Item = Application.ActiveInspector.CurrentItem
Item.Categories = "SendMe"
Item.Save
End Sub

Interesting - I just had the same issue. Working perfectly but then I restarted Outlook and it stopped working - for no apparent reason.
Took me a while to work this out - but when you restart Outlook it applies Macro security permissions to your macro.
If you haven't digitally signed your macro, the default behaviour is to prevent it from running.
You can relax the security settings so that Outlook with either ask your permission to run macros, or just run all macros regardless (this latter option is probably not a good idea!)
You can self-sign your own macro, there's quite a good guide to doing that here: http://www.slipstick.com/developer/how-to-use-outlooks-vba-editor/
But annoyingly it seems you will always get a notification, even with a signed macro... so it's probably easier to just change the security settings to 'notification for all'.
Hope this helps - the code you posted certainly helped me, it was exactly what I was looking for, also to control 1 minute delay!
Man, every time I go near macros in Outlook I end up losing half a day or so...

Related

Outlook Macro Executes even when deleted

I can usually find an answer by searching the forum and applying my own answer but this has me stumped.
I have some vba in ThisOutlookSession that when a mail item is sent from a shared mailbox it moves that item into the sent items of the shared mailbox rather than the individuals. This has been working fine for roughly about a year...
For some reason in the last two weeks or so it has suddenly started to put two copies of the message into the shared mailbox sent items.
Whilst investigating this I noticed something, I entered a Stop line at the start of my code to allow me to step through it. The code fires, hits the Stop line and Stops as it should, however the item has already moved into the shared mailbox... I then step through the rest of the code and it moves the item again...
This is already strange, but what really got me is I have now deleted the code from the session (all of it nothing left), closed Outlook and rebooted the PC. I then sent a test message and guess what - its once again moved into to the shared mailbox sent items.
I haven't got any rules set up, so it cant be that... I only use ThisOutlookSession in Outlook, so its not firing from another Module
It's as though my script still exists in the background but I am unable to see it.
So my questions are:
1) has anyone else experienced this?
2) how is it possible for code to excecute when it doesn't exist (surely this is the equivalent of a human walking around without a head??)
3) does anyone have any solutions on how to resolve this?
I really hope someone out there can help because this has me completely stumped!
TIA

Restricting Excel sheet to open only within organization network

I want to restrict Excel sheet to open only within my organization's network. If my system is connected with company's internet, only then it should get open. If the system is not connected to internet or connected with outside network, it should not get open.
I am using Macro for this. I have used the below code so far, found this on another answer on Stack Overflow. This code is giving same value for a system in different connected network. This will work only if the system is different. but not for different networks.
Option Explicit
Enum COMPUTER_NAME_FORMAT
ComputerNameNetBIOS
ComputerNameDnsHostname
ComputerNameDnsDomain
ComputerNameDnsFullyQualified
ComputerNamePhysicalNetBIOS
ComputerNamePhysicalDnsHostname
ComputerNamePhysicalDnsDomain
ComputerNamePhysicalDnsFullyQualified
End Enum
Declare Function GetComputerNameEx Lib "kernel32" Alias "GetComputerNameExA"
( _
ByVal NameType As COMPUTER_NAME_FORMAT, _
ByVal lpBuffer As String, _
ByRef lpnSize As Long) As Long
Sub test()
Dim buffer As String
Dim size As Long
size = 255
buffer = Space(size)
GetComputerNameEx ComputerNameDnsFullyQualified, buffer, size
Debug.Print Left$(buffer, size)
End Sub
I'll respond even though there was no actual question in your post, and it will probably get closed unless you edit it to add information about a specific programming-related issue, along with examples, detail of what you've tried, and an actual question. (See this and this and this.)
The short answer is:
IT'S NOT POSSIBLE.
Anyone who really wants to access your workbook (or any other Office document) can do a quick Google Search to bypass any security "features" you add.
AUTO_OPEN macros and On Open events can be easily bypassed by holding Shift while opening, or distrusting macros in their Trust Centre. (Here is the first result of a Google search on the topic.)
Passwords can be cracked within minutes using freeware utilities or manually with only a few steps. (See my answer here.)
If the people you are concerned about are not computer-savvy, I suppose you could have the workbook silently notify you of where it's being opened (for example, the IP address or computer name)) but, once again, these could be faked or bypassed altogether.
Assuming the issue is concerns over employees using the workbook (or the data it contains) for "unapproved purposes", the ideal solution would be to either start trusting your staff, or if that's not possible, you need to fire them and find people you do trust.
Edit: Bypassing Workbook_Open
Here's an example of a workbook with a Workbook_Open event, first opened normally, then bypassed by opening the workbook a slightly different way:
Edit: Prevent Any Code From Running
As a developer, I often keep my macro security settings reduced or off. However, a default installation has security turned on, and even if it was disabled, it's not hard to re-enable security in:
File ➡Options ➡Trust Centre
You can't force code to run or bypass security programmatically.
Anything you think you can do or find or do to force code to execute without the user's consent will not work, and at the very least will have a workaround.
Why?
Compare it to Virus Scanner software.
Imagine what would happen if code was able to disable your Virus Scanner? That would make all Virus Scanners absolutely useless, forever. If it were possible, virus creators would be doing it routinely.
The same goes for VBA Macro security options: If it could be bypassed programmatically, the "options" wouldn't have any point and wouldn't even be included. It's not a matter of convenience; it's a matter of security.

Outlook VBA Autosave Attachments Rule - Downloadstate is zero?

I have a rule which starts a sub in VBA when a new eMail arrives.
The code automatically saves the attachment of the Mail in a specific folder.
This worked fine, as long as..... I reinstalled the system.
I added everything like it was, but now I'm suffering the following problem:
When the rule hits in, the eMail Object always has zero attachments. I was sniffing around a little bit and found out, that the Downloadstate is still zero (header only) when the sub runs.
On the web we can see lots of code snippets around for this functionality but Downloadstate seems never to be a topic. So it wasn't for me in the past!
What is wrong here? Why is the Downloadstate zero when the VBA Sub starts?
I found a little workaround by querying the downloadstate and re-run the procedure again with the same mail item. This loop works fine. Almost on the next run it seems that the message is fully downloaded already... And the procedure takes place like it should. But as i know that it worked fine right before, I just want to get rid of this again...
Can anybody help?

Application.restart - Puzzling behaviour in VB.Net

OK guys, what's going on here?
In this VB code:
Module Module1
Sub Main()
If MsgBox("Restart?", MsgBoxStyle.OkCancel) = MsgBoxResult.Ok Then
Application.Restart()
MsgBox("restarting")
Else
MsgBox("Cancel")
End If
End Sub
End Module
If this code is contained within a module, Application.Restart does not end the running application till the End Sub is hit. Any code that appears before then is executed - eg the 'Restarting' messagebox appears.
However, if the equivalent code is run within a form then Application.Restart terminates the running application immediately.
(Both cases correctly start a new instance). This behaviour does not appear to be documented anywhere - the implication in the docs is that it's synonymous with 'End' as far as the termination of the running instance is concerned. Am I missing something?
The best way to answer these questions it to look at the code itself using Reflector (or Microsoft's free for debugging code, when it is available).
With Reflector, you can see (in .NET Framework 4.0) System.Windows.Forms.Application.Restart looks for four different types of applications:
the initial check that Assembly.GetEntryAssembly is Nothing, throwing a NotSupportedException if it is;
the Process.GetCurrentProcess.MainModule.FileName is ieexec.exe in the same folder as the current .NET Framework (specifically the folder where the module defining Object is);
ApplicationDeployment.IsNetworkDeployed is True; and
the general case.
All three supported cases determine the method to start the process again, calls Application.ExitInternal and starts the process again.
Application.ExitInternal closes open forms, including the check for a form attempting to abort the close by setting FormClosingEventArgs.Cancel to True. If no form attempts to cancel, the forms are closed and, using ThreadContext.ExitApplication, all ThreadConnexts are cleaned up (Disposed or their ApplicationContext.ExitThread is called).
NB No Thread.Abort is called, so threads are NOT explicitly ended in any way. Also the Windows.Forms ModalApplicationContext, does not even call the ThreadExit "event" that a normal ApplicationContext does.
(Note that all three supported cases in Application.Restart ignore the result of Application.ExitInternal, so if a form does attempt to abort all that happens is any other forms don't get a chance to close, and the ThreadContexts are not cleaned up!)
Importantly for your question, it does NOT attempt to actually exit the current threads or the entire application (other than closing open forms and thread contexts).
However, by the time your MsgBox("restarting") executes the new application has been started.
You need to manually exit the application after calling Application.Restart. In the case of "run[ing] within a form" (you don't show the code where you tested this) either the form is closed and that is what you considered as the current application ending, or extra stuff that Windows.Forms (or VB) sets up means the application is exited by one of the "events" that throw when the clean up that does occur runs.
In other words, before testing it I expected the MsgBox to appear even when this code is in say the Click event of a form, with the form disappearing first, and the application restarting at the same time.
Having tested it, the MsgBox tries to appear, as I hear the beep that corresponds to it, and if I comment it out the beep does not occur. So something causes the application to exit even though it should have a message box open, and even putting a MsgBox in a Finally outside of the Application.Run does not appear on a Restart. (Note a similar effect is seen if you call MsgBox after Application.Exit.)
So something set up by Windows.Forms (or VB) does actually call something like Environment.Exit which calls the Win32Api ExitProcess and does not regard Finally or call Dispose or Finalize.
Note the Application.Restart documentation implies it is not for Console Applications though it currently works fine (except for the not quitting straight away, which is not implied by Application.Exit).
I am able to restart the application by closing and disposing all open forms, except the one that is calling.
For j As Integer = Application.OpenForms.Count - 1 To 0 Step -1
Dim frm = Application.OpenForms(j)
If frm.Text <> callingForm.Text Then
frm.Close()
frm.Dispose()
End If
Next
Application.Restart()
This is going to be, admittedly, a bit of a guess based on some fairly top-level reading I've done about Application.Restart(), but I think this is occurring due to the way Restart operates internally.
I think Restart() tries to do as much "intelligent" cleanup as it can for a process that is being terminated, and in what may be considered a fairly simplistic implementation, tracks certain of the things to be "cleaned up," possibly calling Dispose() on them (if applicable), which normally is a reasonable step to take. In your case, I'm going to make the guess that a background thread, or form, holds a reference to something - can't say what - that prevents the code from shutting down. It may become aware that it is executing inside a method, and wants to give that method a chance to complete before killing it - waiting on the completion of that sub/method.
I've seen other instances of Restart actually causing a really strange "Collection was Modified" error when no collection was involved. That's suggesting to me, probably naively, that the internal cleanup Restart is trying to achieve is reposed in a simple list, but in certain circumstances, the cleanup modifies the element in an unexpected way, a way that modifies the collection, causes the exception to be thrown, and aborts the exit/restart.

Sending Multi-threaded SendEmail request returns General Mapi Failure

I'm using the MAPI code by Dave Brooks.
I am attempting to programatically send out a Crystal Report that is generated.
When I run through the code without threading everything runs fine. The problem is when I use threading I get the return error "General MAPI failure [2]".
I have never used threading before and understand that there are dangers involved. Can anyone provide any insight into this issue? NOTE: I've removed exception handling to make the code clearer.
Private Sub RunReport()
SetParameters()
SaveReportFile()
Dim operation As New ThreadStart(AddressOf SendEmail)
Dim theThread As New Thread(operation)
theThread.Start()
End Sub
Public Sub SendEmail()
Dim m As MAPI
m = New MAPI()
Dim email As String
For Each email In emailAddress
m.AddRecipientBCC(email)
Next email
m.AddAttachment(#"c:\temp\report.pdf")
m.SendMailPopup("Requested Report", "")
End Sub
A very late answer, but thought I'd add it anyway as I just encountered this and couldn't find an answer elsewhere.
You need to set your thread's appartment state to STA before it is started using:
theThread.SetApartmentState(ApartmentState.STA);
Note that threads from the threadpool (e.g. used by BackgroundWorker component) are MTA.
I encountered this same error (General MAPI failure [2]) and came across this solution early in my debugging; however, the cause for my error was due to running my application as administrator while outlook was running as my user. I had a hard time finding the cause of my error so hopefully this will help someone on the same search as me.
If the above answer doesn't solve your problem, try running your application without elevated privileges if possible or find a way to call MAPI using user impersonation.