This query can be used to solve this issue
SELECT m1.*
FROM messages m1
INNER JOIN
(
SELECT t.v1 AS sender_id, t.v2 AS receiver_id, MAX(t.timestamp) AS maxTime
FROM
(
SELECT CASE WHEN sender_id < receiver_id THEN sender_id ELSE receiver_id END AS v1,
CASE WHEN sender_id < receiver_id THEN receiver_id ELSE sender_id END AS v2,
timestamp
FROM messages
) t
GROUP BY t.v1, t.v2
) m2
ON ((m1.sender_id = m2.sender_id AND m1.receiver_id = m2.receiver_id) OR (m1.sender_id = m2.receiver_id AND m1.receiver_id = m2.sender_id)) AND m1.timestamp = m2.maxTime
UNION ALL
SELECT m1.*
FROM messages m1
INNER JOIN
(
SELECT MAX(timestamp) AS maxTime
FROM messages
GROUP BY group_id
) m3
ON m1.timestamp = m3.maxTime