I created an Excel spreadsheet that my boss wants to put on the company's internal website. The spreadsheet contains some seldom-used, esoteric, but handy functions that only certain employees within the company will find really useful.
The problem is that I don't know who the future users are, and my boss wants me to identify who uses my spreadsheet.
He asked that I password-protect the Excel spreadsheet in such a way that one password does NOT unlock all of the copies that people can download from the site. For example, I can't just make the password "stackoverflow" because once a user legitimately gets the password from me, and is shared with other people, it can be used by anyone within the company to unlock all subsequently downloaded spreadsheets. I will never be able to ascertain who is using the spreadsheet. Also, I cannot modify the website, so I hope to achieve this tracking of users through Excel and email.
Is there a way to have Excel randomly generate a string, which the user emails me, and then I respond with the appropriate password that will unlock the file (based off the generated string)? This requires the user to check in with me before using the spreadsheet (the ideal situation).
Is such an arrangement possible in Excel 2010 Professional Plus?
I think password protection in the method you describe is unnecessarily cumbersome if it is even doable at all.
He asked that I password-protect the Excel spreadsheet in such a way that one password does NOT unlock all of the copies that people can download from the site.
I can't imagine how this might be possible using only Excel. Maybe an Add-in could do this, but at the file level, I don't think it could be done, at least not easily.
I will never be able to ascertain who is using the spreadsheet.
It sounds like this is the really important bit. You are not using the password as a security measure, only as a gatekeeping method to determine who is using the file. This can be automated in other ways, easiest of which would be to use certain Environment variables, e.g.:
MsgBox Environ("username") will display a message box with the current user's name.
You can assign Environ("username") to a string variable, and then you could for example automate Outlook to send you an email that "John Doe has opened the file", or something to that effect. If you want to avoid getting an email every time, you could do some tweaking with a Named Range variable in the Excel file, so that the macro will only send the email once, etc.
Alternatively, you may be able to write a log/txt file to a shared network location (of course, assuming the user is connected to the network) instead of sending emails.
Update
Here is some example code that I've taken from places around the web, it will send an email from the user. You will have to modify the sendTo lines to use your email address as recipient, etc.
Put this in the Workbook's code module, it should email you any time they open this file:
Option Explicit
Private Sub Workbook_Open()
' This example uses late-binding instead of requiring an add'l reference to the
' MS Outlook 14.0 Object Library.
Dim oApp As Object 'Outlook.Application 'Object
Dim ns As Object 'Namespace
Dim fldr As Object 'MAPIFolder
Dim mItem As Object 'Outlook.MailItem
Dim sendTo As Object 'Outlook.Recipient
Dim bOutlookFound As Boolean
On Error Resume Next
Set oApp = GetObject(, "Outlook.Application")
bOutlookFound = Err.Number = 0
On Error GoTo 0
If Not bOutlookFound Then Set oApp = CreateObject("Outlook.Application") 'New Outlook.Application
'# Set the namespace and folder so you can add recipients
Set ns = oApp.GetNamespace("MAPI")
Set fldr = ns.GetDefaultFolder(6) 'olFolderInbox
'# create an outlook MailItem:
Set mItem = oApp.CreateItem(0) 'olMailItem
'# assign a recipient
Set sendTo = mItem.Recipients.Add("YourName#Company.Com")
sendTo.Type = 1 'To olTo
'# assign another recipient
Set sendTo = mItem.Recipients.Add("YourManager#Company.Com")
sendTo.Type = 1
'# Validate the recipients (not necessary if you qualify valid email addresses:
For Each sendTo In mItem.Recipients
sendTo.Resolve
Next
mItem.Subject = "A user has opened the Excel file"
mItem.Body = "This is an automated message to inform you that " & _
Environ("username") & " has downloaded and is using the file."
mItem.Save
mItem.Send
'If outlook was not already open, then quit
If Not bOutlookFound Then oApp.Quit
Set oApp = Nothing
End Sub
Expanding on David's answer you could also use a macro that auto-runs when the sheet is opened and it could write Environ("username") to the next available row in a hidden worksheet. I've used Environ("username") before and it is quite useful, quick, and easy.
This sub on any worksheet will automatically run (IIRC):
Private Sub Auto_Open()
End Sub
You could also put a time stamp in the next column to show when the spreadsheet was used...
Related
I have an Excel add-in published that allows customers to retrieve/send data from a Spreadsheet to my application. The first add-in screen asks the users to provide valid credentials (of my app) before proceeding. These credentials are a user name and an API Key. Some customers are complaining they need to enter the 40-digit long API key every time they want to use the add-in.
My question is: is there a way to safely store these credentials within the add-in? I can't store them on the spreadsheet, since the users just use a temporary one to retrieve/edit the data - and just close Excel after doing it.
It's not really unusual to require a passcode of some kind every time a user starts another session with an app. Facebook and most other online services work this way. Is it the sheer length of the key that bothers your users?
At any rate, if the workbook isn't being preserved, then you can't store it in the document and the add-in has no way to store it locally because web apps don't have access to the file system (except for cookies).
You could store the key in a cookie. Another possibility is LocalStorage.
I've built something like this and used the PERSONAL.XLSB to address this. Important to note that this is not very secure and anyone who had access to person's laptop/account could probably extract it once saved.
Const namedReference = "userAPI"
Sub storeOnLocalMachine()
Dim theAPIKEY As String, wkbk As Workbook
theAPIKEY = "sample123key" 'maybe have them enter once as inputbox
For Each wkbk In Application.Workbooks
If wkbk.Name = "PERSONAL.XLSB" Then Exit For
Next wkbk
If wkbk Is Nothing Then
'figure out how to open silentely open for user
End If
wkbk.Names.Add Name:=namedReference, RefersToLocal:="=""" & theAPIKEY & """", Visible:=False
wkbk.Save
End Sub
Function retrieveTheAPI() As String
Dim wkbk As Workbook
For Each wkbk In Application.Workbooks
If wkbk.Name = "PERSONAL.XLSB" Then Exit For
Next wkbk
retrieveTheAPI = Evaluate(wkbk.Names(namedReference).RefersTo)
End Function
I have made an userform excel system to SignUp or Login users to a kind of quizz. All this files are available on sharepoint of my company to be run. When someone SignUp, all information he had written in the userform are sent to an external workbook that gathered all users inscriptions. All works find individually, but when two people or more are submitting their signup data barely at the same time, their is a conflict in the external workbook because the users overwrite what the earliest one as putted into the cells while I asked to write in the next empty row. I think this is because, the external workbook has not the time to update on SharePoint what the very previous user as written.
To avoid this trubble, I have decide the CheckOut if an other user is already writting in the external workbook. However, I have a kind of similar issue with the CheckOut VBA code lines I used below. When the two users send their data barely at the same time, they come togather in the "CanCheckOut", then one of them succed to checkout the workbook, but the other one is bring to a message box who say "The workbook is already checkout. Would you like to open the file as readOnly or cancel file opening". My wish is that that only one of the users enter in the "If CanCheckOut Then", or to close automaticaly in VBA the messagebox for the second user trying to checkin. I don't know if I can avoid the two users to come inside this "if" because it could a standard lag of syncronisation due to SharePoint. So I tryed the second solution that is to close automaticaly in VBA the messagebox for the second user trying to checkin, however it seems that "Application.DisplayAlerts = False" or "On Error GoTo ErrorUser" don't work so I am kind of stuck and looking for your help and your experience in VBA with multi-users configurations on SharePoint to solve this issue.
Sub UseCheckOut()
Dim App As New Excel.Application
Dim wBook As Excel.Workbook
Dim FileNameUser As String
FileNameUser = ThisWorkbook.Path & "/Support/UsersData.xlsm"
If Workbooks.CanCheckOut(FileNameUser) = True Then
Workbooks.CheckOut FileNameUser ' When two users run the code simultaneously they
' both come to this line
Set wBook = App.Workbooks.Open(FileNameUser)
Else
MsgBox "Someone else signup to the quizz. Please, submit you registration again"
Exit Sub
End If
End Sub
I have a report that I send out daily.
In it there is a linked image to a range that I need to paste into an email and send.
I have the email saved as an outlook template file that I modify as necessary when I need to.
The code I have runs from Excel.
I create an Outlook object and open the Outlook email from the .oft template file, then I want to find the identifier text (INSERT IMAGE HERE) and replace it with the linked image from Excel, which has been copied from the clipboard.
I am trying to add it as an InLineShape so that it behaves properly in the body of the email.
I have been attempting to do it with a defined WordEditor from the body of the email.
I looked into HTML to do it, but I decided the WordEditor object would be a better approach.
After I paste it, I need to set the scale height to 0.75 so that it is displayed properly.
From there, just click send.
Here is a quick sample of my code:
Set OutlookApp = CreateObject("Outlook.Application")
Set OutlookEmail = OutlookApp.CreateItemFromTemplate(templatePath)
OutlookEmail.Display 'Just for code checking
ThisWorkbook.Worksheets("Email Sheet").Pictures("Summary Email Screenshot").Copy
Set EmailText = OutlookEmail.GetInspector.WordEditor
With EmailText.Range.Find
.ClearFormatting
.Execute findText:="*INSERT IMAGE HERE*", MatchWholeWord:=True, MatchCase:=True, _
MatchWildcards:=False, ReplaceWith:="^c", Replace:=wdReplaceOne
End With
EmailText.InlineShapes(EmailText.InlineShapes.count).ScaleHeight = 75
'OutlookEmail.Send
The problem arises with that last line before I send it.
What happens is it is not inserted as an InLineShape, but just a shape so that it floats on top of the text.
I need it as an InLineShape so that the content after the image moves down and is displayed rather than being covered by it.
I've been scowering forums for a while to try to find an answer but to no avail.
I am pretty well versed in Excel VBA, but this is my first attempt at Outlook and Word VBA so please, bear with me.
By default when an image is pasted Word will use the setting Insert/paste pictures as from File/Options/Advanced, section "Cut, copy and paste". So on some machines an image might be pasted as an InlineShape and on others as a Shape.
If you were simply pasting in the code then using PasteSpecial it would be possible to specify inline or with text wrap using the corresponding WdOLEPlacement enumeration value of either wdFloatOverText or wdInLine.
Since the paste command is coming from the ^c replacement text this approach won't work for this situation. That means the Options setting will need to be changed. And, in order for this to be user-friendly, at the end of the code it should be changed back.
Here's some sample code demonstrating how to check the current option, change it if necessary, and reset at the end of the procedure. I'm not familiar with using Word through the Outlook object model, but I think I've correctly instantiated an object for the Word.Application so that VBA executing in Excel or Outlook will know what Options are meant. Except for the last line, this should come between Set and With in the code sample in the question.
Dim wrapType As Long
Dim wordApp as Object
Set wordApp = EMailText.Application
wrapType = wordApp.Options.PictureWrapType
If wrapType <> wdWrapMergeInline Then
wordApp.Options.PictureWrapType = wdWrapMergeInline
End If
'Do other things, then reset
wordApp.Options.PictureWrapType = wrapType
I am trying to edit an existing macro that sends out each row of a spreadsheet as an email. I want the macro to send out these emails in batches instead of all at once.
I am using .DeferredDeliveryTime to do this.
The macro that I have has this at the end
Set olMail = Nothing
Set olApp = Nothing
My question is if I remove this part will my deferred emails still be sent. I am afraid these lines will close outlook and the emails won't be sent.
Setting to Nothing isn't necessary(in modern Excel versions 2010+). but there were issues with older versions of Excel (for which the workaround was to explicitly set).
It's just release an object and clear memory in VBA. For more information, you can refer the following link:
When should an Excel VBA variable be killed or set to Nothing?
Does anyone have excel vba code to copy and paste to loop through gmail emails in a gmail inbox?
While there is a ton out there about:
1) sending gmail with excel vba;
2) looping through emails with excel vba in outlook; and
3) looping through gmail emails in a gmail inbox using other programming languages;
I couldn't find anything to loop through gmail emails in a gmail inbox.
I know I'm actually asking for quite the finished product. It's not that I'm hoping that anyone would be so kind as to write the code for me, but I am hoping that someone might have it already.
After all my attempts to tweak the code I was able to find relative to 1), 2) and 3) above, it became clear to me that I just need to go ahead and post this question. (Who knows, it may help a ton of other folks too.)
You just need to use the names of the folder, check the following
Sub SetFlagIcon()
Dim mpfInbox As Outlook.Folder
Dim obj As Outlook.MailItem
Dim i As Integer
Set mpfInbox = Application.GetNamespace("MAPI").Folders("john.smith#gmail.com").Folders("[Gmail]").Folders("Sent Mail")
' Loop all items in the Inbox\Test Folder
For i = 1 To mpfInbox.Items.Count
If mpfInbox.Items(i).Class = olMail Then
Set obj = mpfInbox.Items.Item(i)
For Each Recipient In obj.Recipients
If Recipient.Address = "myfriend#hotmail.com" Then
'Set the yellow flag icon
obj.FlagIcon = olYellowFlagIcon
obj.Save
End If
Next Recipient
End If
Next
End Sub