Digital sign of Email - VBA - vba

I have received a macro which was written by someone else and I need to repair it. It should digital sign e-mail. I have identified that this function causes an error:
Private Function AddControll(piIcon As Integer) As Boolean
Dim oContr As Object
Dim oCBs As Object
Set oContr = gmyMail.GetInspector.CommandBars.FindControl(, piIcon)
If oContr Is Nothing Then
Set oCBs = gmyMail.GetInspector.CommandBars
Set oContr = oCBs.Item("Standard").Controls.Add(, piIcon, , , True)
End If
End Function
gmyMail is type Outlook.MailItem and when should be e-mail signed digitally then this function is called with piIcon=719
I cannot find out what is wrong. Somewhere I have read that this codes for CommandBars changed since Outlook 2010 but I cannot find actual codes and also I am not sure what exactly this CommandBars should do... Does it assign an icon into the e-mail?

Related

Adding attendees to Outlook AppointmentItem (VB.NET)

I am trying to make an application in which i can send appointments to co-workers.
My code is as follows:
Public Sub SendAppointment()
Dim TempApp As Outlook.Application = New Outlook.Application()
'An AppointmentItem 'TempAppItem' object represent one appointment
Dim TempAppItem As Outlook.AppointmentItem = TempApp.CreateItem(Outlook.OlItemType.olAppointmentItem)
TempAppItem.Subject = Onderwerp.SelectedItem
TempAppItem.Body = Opmerking.Text
'Set Location
'TempAppItem.Location = "No Location"
'Set start and end date and times
TempAppItem.Start = Convert.ToDateTime(Btijd.SelectedItem)
TempAppItem.End = Convert.ToDateTime(Etijd.SelectedItem)
'Save to Calendar.
TempAppItem.RequiredAttendees("some#emailaddress.com")
TempAppItem.Send()
TempAppItem.Save()
TempApp = Nothing
TempAppItem = Nothing
End Sub
If I leave out:
TempAppItem.RequiredAttendees("some#emailaddress.com")
It creates the appointment in my own calendar. This proves the rest of the code works. But somehow no matter which argument i add to RequiredAttendees, I keep getting errors. Mostly saying "Too many arguments to 'Property RequiredAttendees As String'.
In my eyes the easiest would be if I can just use the users e-mailaddress as a value to a variable, but somehow it seems vb.net only uses the stored name of said contact, which doesn't seem to work :\
I can't find any explanation of how to properly set the RequiredAttendees property and I am starting to break my head over this. Can anyone help me out or at least push me in the right direction?

How to Edit a Read-Only Word Document (VBA)

I am periodically getting Word documents from various clients and sometimes they send them to me in 'Read-Only' mode. While it isn't a big deal to go to 'View > Edit Document' manually, I cannot seem to find how to do this within my VBA code.
Either opening a document as editable or toggling it as editable once it is open would be sufficient for my needs.
Note that I cannot open the document with 'readOnly = false' as it looks like it is set to 'readOnly recommended' (based on my reading of the MS man page on Document.Open).
IN CONTEXT:
I was also hitting a problem with turning off 'read-mode' which the documents were opening as by default. I have posted this question and answer here.
The code below will change the ReadOnly attribute of a closed file, setting its ReadOnly attribute to either True or False depending on the argument supplied to the procedure.
Private Sub SetReadOnlyProperty(Fn As String, _
ByVal ReadOnly As Boolean)
' 21 Nov 2017
Dim Fso As Object
Dim Doc As Object
Set Fso = CreateObject("Scripting.FileSystemObject")
Set Doc = Fso.GetFile(Fn)
If (Doc.Attributes And vbReadOnly) <> Abs(Int(ReadOnly)) Then
Doc.Attributes = Doc.Attributes Xor vbReadOnly
End If
End Sub
This procedure requires access to the MS Scripting Runtime DLL. Enable this access by checking the box against Miscrosoft Scripting Runtime from Tools >References in the VBE window. Below is an example of how to call the function. Note that an error will result if the supplied file doesn't exist.
Private Sub TestReadOnly()
SetReadOnlyProperty "H:\Test Folder\Test File.docx", False
End Sub

VBA Outlook script error: an object could not be found

I am trying to use a VBA script to pull info from the emails in Inbox into an excel spreadsheet:
'Subject
'To Address
'From Address
'CC Addresses
it fails for senders who have already left the organization and they're no longer in O365.
This is the code bit:
Function X400toSMTP(strAdr As String) As String
Dim olkRcp As Outlook.Recipient, olkUsr As Outlook.ExchangeUser
Set olkRcp = Session.CreateRecipient(strAdr)
If olkRcp.AddressEntry = Empty Then
X400toSMTP = strAdr
ElseIf olkRcp.AddressEntry.AddressEntryUserType = olExchangeUserAddressEntry Then
olkRcp.Resolve
Set olkUsr = olkRcp.AddressEntry.GetExchangeUser
X400toSMTP = olkUsr.PrimarySmtpAddress
End If
Set olkRcp = Nothing
Set olkUsr = Nothing
End Function
I ran the debug and it stops at AddressEntry : The attempted operation failed. An object could not be found
I'm trying to find a way to make the script leave the address field empty for those senders who cannot be found on O365 anymore and further process the rest of the items in the Inbox.
I have tried the below:
If IsNull(olkRcp.AddressEntry) Then
X400toSMTP = strAdr
but am still getting the same error for AddressEntry.
I am just a VBA noob so would very much appreciate your advice.
Many thanks!
Make sure the recipient is resolved before accessing the AddressEntry property - call olkRcp.Resolve.

How to get the email address of the current logged-in user?

I'm new to VBA and trying to get an automated word document working. At the moment there is a Button in the document that which upon pressing, will fire off an email with the document attached.
However I need to also get the email address of the current user sending the email, so I can place it inside the document before sending it off. My searches on the internet have not resulted in any usable code that meets my situation. My current code is below.
Set OL = CreateObject("Outlook.Application")
Set EmailItem = OL.CreateItem(olMailItem)
Set Doc = ActiveDocument
Doc.Save
With EmailItem
.Subject = "Requesting Authorization Use Overtime"
.Body = "Please review the following request for overtime" & vbCrLf & _
"" & vbCrLf & _
"Thanks"
.To = "toemail#test.com"
.Importance = olImportanceNormal
.Attachments.Add Doc.FullName
.Send
End With
Not sure if this is relevant, but when the document is being used, the Outlook application will always be open with a user signed in. Im used to having intellisense help in these sorts of situations so I can fool around with methods and properties, but there seems to be very little help from intellisense.
It all depends on the definition of "the current user address".
The address of the primary account in Outlook can be retrieved from Appication.Session.CurrentUser (returns Recipient object). Use Recipient.Address property. Note however that for an Exchange account (Recipient.AddressEntry.Type == "EX") you will receive an EX type address. To retrieve the SMTP address, use Recipient.AddressEntry.GetExchangeUser().PrimarySmtpAddress. Be prepared to handle nulls/exceptions in case of errors. This is what you most likely need in your particular case.
On the Extended MAPI level (C++ or Delphi), use IMAPISession::QueryIdentity (you can test it in OutlookSpy (I am its author) - click IMAPISession button, then QueryIdentity). You can then read the PR_ADDRTYPE property ("EX" vs "SMTP") and PR_EMAIL_ADDRESS (when PR_ADDRTYPE = "SMTP") or (in case of Exchange) PR_SMTP_ADDRESS (not guaranteed to be present) and PR_EMS_AB_PROXY_ADDRESSES (multivalued property will Exchange addresses, including all proxy (alias) addresses).
In case of multiple accounts in the profile, an email can be sent or received through multiple accounts. In that case use MailItem.SendUsingAccount (returns Account object, can be null - in that case use Application.Session.CurentUser). This is valid both for received, sent or emails being composed (Application.ActiveInspector.CurrentItem or Application.ActiveExplorer.ActiveInlineResponse).
All accounts in a given profile can be accessed using the Namespace.Accounts collection (Application.Session.Accounts). Account's address can be accessed using Account.SmtpAddress property.
Note that the Outlook Object Model only exposes mail accounts. Some store accounts (such as PST) are not in the collection since they do not have an intrinsic user identity even if some other accounts (such as POP3/SMTP) can deliver to that store. If you want to access all accounts, you can use Redemption (I am its author) and its RDOSession.Accounts collection (RDOAccounts object).
On the Extended MAPI level, the accounts are exposed through the IOlkAccountManager interface. You can play with it in OutlookSpy if you click the IOlkAccountManager button.
In case of delegate Exchange stores, the store owner is not exposed through the Outlook Object Model. You can either use Extended MAPI (note that the PR_MAILBOX_OWNER_ENTRYID property is only exposed by the online store, it is not available in a cached store). You can parse the Exchange store entry id and extract the EX type address from it. You can then construct the GAL object entry id given the EX address. You can also access the store owner using Redemption and its RDOExchangeMailboxStore object and its Owner property.
Usually, the email address is the name assigned to Outlook Mail Folders.
So try this:
'~~> add these lines to your code
Dim olNS As Outlook.NameSpace
Dim olFol AS Outlook.Folder
Set olNS = OL.GetNamespace("MAPI")
Set olFol = olNS.GetDefaultFolder(olFolderInbox)
MsgBox olFol.Parent.Name '~~> most cases contains the email address
This is assuming your are using Early Bind with the object reference properly set.
Another way to access such info is directly use Namespace properties.
MsgBox olNS.Accounts.Item(1).DisplayName '~~> usually email address
MsgBox olNS.Accounts.Item(1).SmtpAddress '~~> email address
MsgBox olNS.Accounts.Item(1).UserName '~~> displays the user name
I hope any of the above somehow helps.
This answer is for Late Binding so you don't need to have reference libraries. Place the following code in a module:
Dim OL As Object, olAllUsers As Object, oExchUser As Object, oentry As Object, myitem As Object
Dim User As String
Set OL = CreateObject("outlook.application")
Set olAllUsers = OL.Session.AddressLists.Item("All Users").AddressEntries
User = OL.Session.CurrentUser.Name
Set oentry = olAllUsers.Item(User)
Set oExchUser = oentry.GetExchangeUser()
msgbox oExchUser.PrimarySmtpAddress
Functional Approach
To make this a bit more reusable, try any return the email from a function.
Late Binding Example
''
' Creates a new instance of Microsoft Outlook to get the current users
' email address.
' Late Binding Demo.
'
' #exception If any errors it will return an optional parameter for fallback values
''
Public Function GetUsersOutlookEmail(Optional ByVal errorFallback As String = "") As String
On Error GoTo catch
With CreateObject("outlook.application")
GetUsersOutlookEmail = .GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Parent.Name
End With
Exit Function
catch:
GetUsersOutlookEmail = errorFallback
End Function
Early Binding Example
''
' Creates a new instance of Microsoft Outlook to get the current users
' email address.
' Late Binding Demo.
'
' #reference Microsoft Outlook 16.0 Object Reference
' #exception If any errors it will return an optional parameter for fallback values
''
Public Function GetUsersOutlookEmail(Optional ByVal errorFallback As String = "") As String
On Error GoTo catch
With New Outlook.Application
GetUsersOutlookEmail = .GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Parent.Name
End With
Exit Function
catch:
GetUsersOutlookEmail = errorFallback
End Function
Error Handling
Anytime you are making an API call like this, there is always a potential for errors to occur. The method I choose for these demos is to provided an optional parameter for a fallback email. This make is dynamic as you can check to see if it is null, or you could provide something such as username Environ("Username") & "#outlook.com"

Pass Global Variable to custom UserForm

Have the following code that ends up with a .Count variable. I would like to take that integer value and output it to a sentence in a custom UserForm. How do I do this within the Visual Studio 2012 designer. This is really stumping me. Thanks!
Public Shared Property mailItem As Object
Public Shared Property BodyMatchResults As MatchCollection
Public Shared Property SubjectMatchResults As MatchCollection
Public Sub Application_ItemSend(ByVal Item As Object, _
ByRef Cancel As Boolean) Handles Application.ItemSend
Dim mailItem As Outlook.MailItem = TryCast(Item, Outlook.MailItem)
If mailItem IsNot Nothing Then
Dim attachments = mailItem.Attachments
For Each attachment As Outlook.Attachment In attachments
AttachmentQuery(attachment, mailItem, Cancel)
Next attachment
End If
Dim BodyMatchResults As MatchCollection
Dim SubjectMatchResults As MatchCollection
Dim RegexObj As New Regex("\b(?!000)(?!666)(?!9)[0-9]{3}[ .-]?(?!00)[0-9]{2}[ .-]?(?!0000)[0-9]{4}\b")
BodyMatchResults = RegexObj.Matches(mailItem.Body)
SubjectMatchResults = RegexObj.Matches(mailItem.Subject)
If BodyMatchResults.Count > 0 Or SubjectMatchResults.Count > 0 Then
Cancel = True
MessageBox.Show((BodyMatchResults.Count + SubjectMatchResults.Count))
' Access individual matches using AllMatchResults.Item[]
Else
Cancel = False
End If
The UserForm is pretty basic with three buttons and a warning text above it. I would like to have in that text "There were either "BodyMatchResults.count" or "subjectmatchresults.count" in your email.
Well you obviously beging with your .count variable (which for arguments sake I'll assume is of type Integer). Hopefully you also have your Custom UserForm which we'll assume you have called UserForm.
In that UserForm add the following code:
Private _count As Integer
Public Sub New (ByVal count AS Integer)
InitializeCompponent()
_count = count
End Sub
You can then use the _count variable to dipaly the informationyou want displayed.
Now when you call your UserForm you can pass your .count variable to it so that it can be used there like this:
dim frm as New UserForm(NumberOfCountsIWantToDisplay)
This basic principle will work for most situations.
Edit
Clearly I'm not reading things properly. Your question had specifically asked about passing a Global variable. You should simply be able to refer to a publically defined global variable from anywhere within your application (so long as that variable has application scope). However global variables can be more trouble that they are worth and if in reality you simply want to pass one value from form a to form b then I would use the approach that I had originally outlined having misread the subject title, for which I apologise.