I'm using MS Access to create a database with over 5000 contacts. These contacts are separated up into which employee the contact belongs to, and then again into categories for easy searching. What I want to do is create a button that will open up a query in table form (simple), then have check boxes so an employee can select, for example, 100 contacts to send an email to out of the 110 in the table, and then send a mass email such as a newsletter (not so simple!). I've been going nuts trying to work out how to do this as I don't really understand programming (I'm a temp thrown into this job and just doing the best I can) and all I can find on the matter is something about loops (no idea!) and that I need software to do this.
Any solutions for me please? I'd like to avoid buying/installing software if possible and if you do have an answer, please make it as simple as possible...
Thanks in advance!
Kate
I have just created the following working example in MS Access 97.
A sample table (I tested the code with valid e-mail addresses):
ID Name Email
1 Rics rics#stack.com
2 Kate kate#stack.com
3 X x#stack.com
A form with one button.
The following code is being performed when the button is clicked:
Private Sub Mail_Click()
Dim r As Recordset
Dim email As String
Set r = CurrentDb.OpenRecordset("select * from Addresses")
Do While Not r.EOF
email = r(2)
DoCmd.SendObject acSendNoObject, Null, Null, email, Null, Null, "Test subject", "Message body of the test letter", False, Null
r.MoveNext
Loop
r.Close
End Sub
I hope you could insert it into your application.
Got it working :)
The code was great but it needed some tweaking to work specifically with my data. After a lot of errors popping up this is what I finally came up with:
Dim r As Recordset
Dim Email As String
Set r = CurrentDb.OpenRecordset("select Email from FranksFinanceBrokers")
Do While Not r.EOF
Email = Email & r(0) & ";"
r.MoveNext
Loop
r.Close
DoCmd.SendObject acSendNoObject, Null, Null, "", "", Email, "", "", True, Null
End Sub
Thanks for ur helps guys!
I think you're going to need to learn some VBA coding to get this done. This tutorial might be useful.
Heres a way to send email from access.
Here's another resource for sending e-mail through MS Access
The answer that rics has supplied will send an e-mail to everyone in a recordset, but it sounds like maybe what you are wanting to do is send a single e-mail to a custom distribution list. To do that, tweak rics' code to build up the address string something like this:
Private Sub Mail_Click()
Dim r As Recordset
Dim email As String
Set r = CurrentDb.OpenRecordset("select * from Addresses")
Do While Not r.EOF
email = email & r(2) & ";"
r.MoveNext
Loop
r.Close
DoCmd.SendObject acSendNoObject, Null, Null, email, Null, Null, "Test subject", "Message body of the test letter", False, Null
End Sub
Kate,
Sorry to say that there is no specific "magic" code for what you plan to to. You will have to write something. My solution would be:
Create a form with 3 controls: 1 text control, 1 listbox control.,1 "send" button
The text control contains the text to send
The list control displays all my available emails (populated with a recordset)
Multiselect will be enabled, so that I can select multiple items in the list
By a click on the button, I will
Concatenate all selected emails to get a "sendTo" string such as
sendTo = "bla#bla.com;blo#blo.com".
Call the doCmd.sendObject method using sendTo + the text string as an argument
Options could be to
Have an extra control for email subject
Keep a trace of sent mails in a table (subject, text, date, people reached). It could be as basic as "one record per mail" with a memo field to record the sendTo text string (Of course you could build something smarter with multiple tables to stick to the many-to-many relation that can be established between your people table and your mail table, but you might not need it)
There are a couple of ways to get around the missing e-mail addresses. The easiest is to adjust your SQL to exclude them:
select Email from FranksFinanceBrokers WHERE (Email IS NOT NULL) AND (Email <> "")
The other approach would be to add an IF statement to the string building code:
IF Not IsNull(r(0)) AND r(0) <> "" THEN Email = Email & r(0) & ";"
I would just filter it at the SQL level -- more efficient and just easier.
Would it be easier to buy software to do this? Yes, but where's the challenge in that? :-) You are already most of the way there, so I'd stick with it.
Emailing from Access has a number of pitfalls, not least of which is that doing so can make you look like a spammer and cause problems with your email host. Plus, there are a bunch of security issues. The best source for information on this is Tony Toews's Email FAQ.
Related
I have set up a student database in ms-access 2016 to track students on support to study and imported all the emails from a folder related to students into a database called emails (I still need to work out the VBA code to update this folder on opening/closing a form). When a student emails me, I can match that email easily to the main database as it is just from them. However, when an email is sent to a student, often other staff members are cc'd in to the email. I therefore need to be able to select out just the student's email name from the To column. So it may be Jo Smith; Leah Jones; Jo Davies (UG) (or any combination of that depending on if the student is the main recipient or not. The name of the student will always have (UG) at the end of the name, so can be identified.
Is there a way of selecting out just the student name (with the (UG) at the end is fine) from the string of names into a new column using an update column? The recipient names are separated by a ; (but if the student is first or last on the list obviously won't have a ' before/after their name). I need this to link it to the name so I can see emails sent to and from the student in forms, alongside their other information.
Many thanks in advance
Ali
It's been over a decade since I wrote an Access VBA UDF and probably a year or 5 since I wrote VBA, so grain of salt here, but this should be in the ballpark:
Function getStudentEmail(emails as String) as String
'Declare array to hold emails
Dim emailsArr() as String
'Split delimited string of emails into the array with split() function
emailsArr = Split(emails, ";")
'Loop through array
For Each email in EmailsArr
'Check if email string has (UG) in it
If InStr(1, email, "(UG)", 1) Then
'Set the return to the email and break the for loop ending the function
getStudentEmail = email
Exit For
End If
Next email
End Function
How to use:
Open up the Visual Basic Editor (VBE) with the "Visual Basic" button in the ribbon under the "Database Tools" section:
Right-click on your database in the "project" pane and choose Insert>>Module:
Paste your code in:
Now you should be able to use this function in your SQL like SELECT getStudentEmail(yourEmailColumn) FROM yourtable;
I have an alert sending aid built into an Access database that sends emails to all technicians with an expired/ing induction, all in one go. Every email requires permission to send.
Similar to this question and this question but I need to send multiple emails automatically all at once, without holding up other processes.
The code in the questions seems to send a single email, and the only accepted answer involves waiting five seconds up to three times to check that the actual message had been displayed so that SendKeys would work on that window.
If I use SendKeys with a 5 second pause built in to wait for confirmation as Graham Anderson suggests, this won't speed up the process, only avoid some clicking. The progress bar shown on the warning (below) takes roughly that time to fill, so I'm guessing that's the system building the email, which is what the wait is for.
The same problem applies to Julia's answer to the other question - the warning box won't let you click "Allow" until the progress bar is full, so code that auto clicks this button will have to wait to complete at best.
I tried DoCmd.SetWarnings (False) (and then DoCmd.SetWarnings (True) after sending) but that doesn't stop this particular one. This may be because the warning comes from Outlook rather than Access.
The coding I have:
Private Sub SendAlerts_Click()
Dim db As Database, rs As Recordset
Dim Subject As String, Body As String, EmailAddress As String
Dim Recipient As String, Induction As String, Expiry As String
Set db = CurrentDb
Set rs = db.OpenRecordset("qryExpiryAlert", dbOpenDynaset)
Do Until rs.EOF
EmailAddress = rs!Email
Recipient = rs!FullName
Induction = rs!Induction
Expiry = rs!ExpiryDate
Subject = "Inductions need renewal"
Body = "Hi " & Recipient & ", the expiry for your " & Induction & _
" certificate is " & Expiry & ". Please send a current certificate asap."
DoCmd.SendObject , , , EmailAddress, , , Subject, Body, False
rs.MoveNext
Loop
DoCmd.Close
End Sub
Here is the warning:
I wrote and compiled an Autohotkey script that looks for the Outlook confirmation dialog and automatically clicks Allow. (I call this from Access VBA and can set how long it run for before shutting itself off.) As you point out, though, there is still a substantial delay waiting for the Allow button to be enabled each time.
Ultimately, our company ended up purchasing Outlook Security Manager. As usual, you have to add an Outlook Security Manager Reference. reference to your project.
It basically has ON and OFF settings, so it's easy to use. If wrote a Sub in a standard module to simplify:
Public Sub SetSecurityManager(State As String)
' Turns the Security Manager on or off.
' The Security Manager allows the application to
' send emails through Outlook without having to
' manually confirm each outgoing email.
Select Case State
Case "On"
' Temporarily turn off Outlook security so we can send email
Set SecurityManager = CreateObject("AddInExpress.OutlookSecurityManager")
SecurityManager.DisableOOMWarnings = True
SecurityManager.DisableSMAPIWarnings = True
Case "Off"
'Restore Outlook security to normal
SecurityManager.DisableSMAPIWarnings = False
SecurityManager.DisableOOMWarnings = False
Set SecurityManager = Nothing
Case Else
End Select
End Sub
Whenever I need it, I add this line to my code:
SetSecurityManager "On"
It's frustrating to have to pay for a solution to a security problem created by software we purchased, but it's the best answer we've found. I ship between 150 and 225 reports a day and have no problem with OSM.
Thanks,
Keith
I am creating a small Access DB for our Data Entry guys. Our main DB is mysql but due to ease of use we are creating an Access DB to make it easier for them to enter the Data. I have done most of it but am stuck with this problem (which I know how to solve in mysql+php) Please pardon my ignorance, but I have just started using MS Access.
I have two tables - ClientPhones and sales. The ClientPhones table has phone, clientid fields. sales table has salesid, clientid, date, etc fields.
I also have a Form which has all relevant fields for the sales table. I want to add a new field, phone_no in that form. When a user inputs the number and on focus lose event, I was access to run a query on the clients table to see if the phone number exists in any of the 3 phone number fields. If it finds a client with that phone number, the client ID should be populated, else a new form to input the client details should be shown.
Is this possible with MS access or am I doing this incorrectly?
Use the text box's After Update event to retrieve the clientid which matches the phone number the user entered.
If a clientid is found, store it in the text box which is bound to clientid.
If no match is found, ask whether the user wants to add a new client, and open that form if they respond yes.
This code outline assumes txtSearchPhone is the name of the text box where the user enters the target phone number, and txtClientId is the name of the text box where you want to store clientid.
Private Sub txtSearchPhone_AfterUpdate()
Dim varClientId As Variant
Dim strCriteria As String
strCriteria = "[phone]='" & Me.txtSearchPhone.Value & "'"
Debug.Print strCriteria '<-- inspect this in Immediate window; Ctrl+g will take you there
varClientId = DLookup("clientid", "ClientPhones", strCriteria)
If IsNull(varClientId) Then
If MsgBox("Add new user?", vbYesNo) = vbYes Then
'DoCmd.OpenForm ... (see Access help topic)
End If
Else
Me.txtClientId.Value = varClientId
End If
End Sub
Make sure the text in txtSearchPhone does not include a single quote character (') because the DLookup will break if it does. You can use the text box's Validation Rule and/or Before Update event to make sure a single quote is not present.
I am having some trouble with MS Access 2010. I am trying to modify a database I downloaded, a template from Microsoft‘s web site, I am doing a little modifying to keep track of the food nutrition. I have some experience with basic from the old days of the 16 bit Atari days. I’m not totally green to VBA, just know enough to get in trouble. I have a Form that uses a select query to populate lower half of the form. I added an attachment field to the foods table which has over 8500 record that is the table for the query. My problem is to add VBA code in a module to see if there is a photo present or not. I want to be able to show an icon grayed out for no photo and a regular icon if there is a photo file. But that's for when I get it work to begin with. I call the function in the field properties:
Photo1: chkAttachment([Photo])
This one to start with gives me and error saying: "The multi-valued field '[Photo]' is not a valid in the expression 'chkAttachment([Photo])'. When I change it to:
Photo1: ChkAttachment([Photo].[FileName])
I get and #Error for the empty fields and a "Has Photo" for the one with a file in it.
The Following code is the function I am referencing To Show what I am trying to do
Public Function chkAttachment(fldPhoto As String) As String
On Error GoTo chkAttachment_Err
chkAttachment = ""
'Debug.Print fldPhoto
If fldPhoto = Null Then
chkAttachment = "No Photo"
Else
chkAttachment = "Has Photo"
End If
chkAttachment_Exit:
Exit Function
chkAttachment_Err:
MsgBox " It don't like Error number: " & Err.Number & " " & Error$
Resume chkAttachment_Exit
End Function
The query won’t even call the code if the attachment is empty. I Googled the following question, and searched on this web site “Microsoft Access 2010 VBA how to query attachment field” without any luck. I have tried to use some code to count the number of files in the attachments, I found in the thread “How to query number of attachments from Attachment field in Microsoft Access?” from Aug 2011, but couldn’t figure out how to get it to work. When it comes to SQL, I’m in the dark with that part.
Thanks for any help that comes my way.
Steven
If you have an Attachment control named [attachPhoto] on your form and that control is bound to the [Photo] field (i.e., the Control Source of the Attachment control is Photo) then you can just check the value of
Me.attachPhoto.AttachmentCount
to see if the record has any attachments.
(Note that if you don't want the users to actually see the [attachPhoto] control you can just set its Visible property to No.)
You can check it in SQL statement " Not (tblxx.Pic.FileData) Is Null " probably in the where clause. I did it this way using a recordset.
I believe this is causing the #ERROR in your field
If fldPhoto = Null Then
Correct checking for Null would be the following:
If IsNull(fldPhoto) Then
But then you might still get a Null exception while calling the function. So you might want to edit your overall code to the following:
If (fldPhoto = "") Then
and when calling the function :
Photo1: ChkAttachment(Nz([Photo].[FileName]))
Hope I helped
I wanted to check if an attachment was made or not before running a query on a form. I made a text box in the form and under control source of the text box, went to expression builder and entered " = [name of column which has the attachment].[AttachmentCount]".
The text box gave me the count as 0(zero) if no attachment is made and 1 for 1 attachment. I could use the text box to condition run my query. All the above in Access 07.
I have written VBA code to send an email from a group mailbox. I set the principal field to say where the mail comes from. It almost works correctly, putting the message in the sent items of the group mailbox. Even though I have the group mailbox name in the Principal field, it still says it was sent my me. I discovered that whichever user looks at the message in sent items, it says it was sent by that user (it is a dynamic field). I want to set that From field, and I discovered I can do that with something like '.from = "(User Name)"'.
So I am aware of the basic variables available, such as .SendTo, .CopyTo, .Principal, .From. But I have done web searches and I can't figure out how to get a comprehensive list of all the variables available. Hopefully someone can point me to some documentation that lists these?
For reference here is my code:
Function EmailFromNotes(strSendTo As String, strCopy As String, strSubject As String, _
strText1 As String, strText2 As String, strText3 As String, _
strText4 As String, strText5 As String, strAttachment As String, strFrom as String)
Dim notesdb As Object
Dim notesdoc As Object
Dim notesrtf As Object
Dim notessession As Object
Dim i As Integer
Dim AttachME As Object 'The attachment richtextfile object
Dim EmbedObj As Object 'The embedded object (Attachment)
Set notessession = CreateObject("Notes.Notessession")
''''''''Group Mailbox'''''''''''''''''''''''''''''''''''''''''''''''''
Set notesdb = notessession.GetDatabase("Servername", "mailin\GroupMailbox.nsf")
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Open the mail database in notes
If notesdb.IsOpen = True Then
'Already open for mail
Else
notesdb.OPENMAIL
End If
Set notesdoc = notesdb.CreateDocument
Call notesdoc.ReplaceItemValue("Subject", strSubject)
Set notesrtf = notesdoc.CreateRichTextItem("body")
Call notesrtf.AppendText(strText1 & vbCrLf & strText2 & vbCrLf & strText3 & vbCrLf & strText4 & vbCrLf & strText5)
'''strCopy = "michael.thain#pnc.com"
notesdoc.SendTo = strSendTo
notesdoc.CopyTo = strCopy
notesdoc.from = strFrom
''''''''Group Mailbox'''''''''''''''''''''''''''''''''''''''''''''''''
notesdoc.principal = "Group Mailbox Name"
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
If strAttachment = "" Then
Else
Set AttachME = notesdoc.CreateRichTextItem(strAttachment)
Set EmbedObj = AttachME.EmbedObject(1454, "", strAttachment)
End If
Call notesdoc.Save(True, False)
notesdoc.SaveMessageOnSend = True
Call notesdoc.Send(False, strSendTo)
Set notessession = Nothing
End Function
Unlike many other mail systems, Lotus Notes is finicky about spoofing the From field. The NotesDocument.Send() method doesn't want you to do it, and will override what you put in there. The Principal field is provided so you can say who you are sending on behalf of, but the From is supposed to be the true name of the actual sender. If you look at the document properties for the message in your Sent folder, I believe you'll find that the From field does indeed contain your name, not the name that your code is trying to put in that field!
There is a way around this, at least for the Sent message. Instead of relying on the SaveMesasageOnSend property, you can just use NotesDocument.Save() to write the document directly to the group mailbox, making sure that you set the PostedDate and not the DeliveredDate so that it will appear in the Sent view. It will be missing other fields that the Domino router would normally have added for you, though, like the MessageID and a few others -- but that might not be important for you. The message should still be viewable. In any case, as complex as it is, the formulas in the fields on the Memo form and its associated subforms in the mail template are your ultimate guide for figuring out how what the user sees is related to the actual values that are stored in the document.
If you're also concerned about making sure that recipients don't see your name, there's another trick. It involves directly writing the message to the router mailbox (the mail.box file). I've seen some systems, however, where there's code in place to prevent spoofing even if you do this, so it's something you'll have to try and see if it will work.
BTW: Are you asking about what the users see when they look at the index of the Sent view? That should be showing the value in the Principal field. Or are you asking about what the users see when go the Sent view and open the message? That should display the Principal field, followed by a newline and then "Sent by:" the From field. (Bear in mind that the From field is not likely the value that your code set due to the anti-spoofing provisions that I described.) Does this match what you are seeing?
Mail fields are defined by an RFC for all mails in general.
http://en.wikipedia.org/wiki/Email#Message_header
RFC 5322 https://www.rfc-editor.org/rfc/rfc5322
In the RFC 5322 Standard the field From has a different purpose than in Lotus Notes, because it is always identifying the owner of the mail.box. Instead of using the field Principal to identify the owner of the mail.box in which an email was written, the field Sender is used to identify the effective user who produced the email.
The field Principal is not (or better said no longer) accepted in the email header by many email providers and bounced back referring to being not RFC 5322 compliant. In messages produced by LotusScript directly in a document saved in the mail.box, you should use the field From instead of the field Principal and add the field Sender for the email address of the effective sender (sent by), who in a regular Lotus Email would be in the field From. If you prefer to have all replies to the effective sender instead of the person identified in the field From (original LN field Principal), you need to add the field ReplyTo with the same address as in der field Sender.