Avoid looping through an array or table if you can. Try something like
SELECT M.*
, C.*
FROM Messages M
INNER JOIN MessageContact MC on M.MessageID=MC.MessageID
INNER JOIN Contacts C on C.ContactID=MC.ContactID
WHERE ContactID in (...)
ORDER BY ContactID, MessageID
You will need to replace the (...) above with a comma-separated list of the contacts selected from your web form e.g. ('1','2','3')
OR
you could insert the contacts into an interim table (e.g. SelectedContacts) and use
WHERE ContactID in (Select ContactID from SelectedContacts)
[Edit - see comments below]
This is a bit mangled as I haven't got anything to run it against on this PC. I'm trying to say just return messages that have been sent to the listed contacts and where the number of recipients for those messages is the same as the count of contacts. There is definitely a tidier way of doing it!
SELECT M.* -- replace with list of stuff from Messages you need
, C.* -- replace with list of stuff from Contacts you need
FROM Messages M
INNER JOIN MessageContact MC on M.MessageID=MC.MessageID
INNER JOIN Contacts C on C.ContactID=MC.ContactID
WHERE M.MessageID in
(Select MessageID from MessageContact M
where ContactID in
(Select ContactID from SelectedContacts)
Group by MessageID
Having count(*) = (select count(*) as ContactCount from SelectedContacts))