diff --git a/libpurple/protocols/ircv3/purpleircv3connection.h b/libpurple/protocols/ircv3/purpleircv3connection.h
--- a/libpurple/protocols/ircv3/purpleircv3connection.h
+++ b/libpurple/protocols/ircv3/purpleircv3connection.h
@@ -159,6 +159,26 @@
 PURPLE_IRCV3_AVAILABLE_IN_ALL
 PurpleConversation *purple_ircv3_connection_find_or_create_conversation(PurpleIRCv3Connection *connection, const char *id);
 
+/**
+ * purple_ircv3_connection_find_or_create_contact:
+ * @connection: The instance.
+ * @nick: The nickname of the user.
+ *
+ * Looks for an existing contact belong to @connection and returns it if found.
+ * If not a new contact will be created.
+ *
+ * THis will only ever return %NULL if @connection is invalid or @nick is
+ * %NULL.
+ *
+ * Note that the ownership of the contact remains with the default
+ * [class@Purple.ContactManager].
+ *
+ * Returns: (transfer none) (nullable): The contact.
+ * Since: 3.0.0
+ */
+PURPLE_IRCV3_AVAILABLE_IN_ALL
+PurpleContact *purple_ircv3_connection_find_or_create_contact(PurpleIRCv3Connection *connection, const char *nick);
+
 G_END_DECLS
 
 #endif /* PURPLE_IRCV3_CONNECTION_H */
# HG changeset patch
# Node ID ca39f20f3ba3
# Parent  8e8f223cdd5a
diff --git a/libpurple/protocols/ircv3/purpleircv3connection.c b/libpurple/protocols/ircv3/purpleircv3connection.c
--- a/libpurple/protocols/ircv3/purpleircv3connection.c
+++ b/libpurple/protocols/ircv3/purpleircv3connection.c
@@ -762,3 +762,25 @@
 
 	return conversation;
 }
+
+PurpleContact *
+purple_ircv3_connection_find_or_create_contact(PurpleIRCv3Connection *connection,
+                                               const char *nick)
+{
+	PurpleAccount *account = NULL;
+	PurpleContact *contact = NULL;
+	PurpleContactManager *manager = NULL;
+
+	account = purple_connection_get_account(PURPLE_CONNECTION(connection));
+	manager = purple_contact_manager_get_default();
+	contact = purple_contact_manager_find_with_id(manager, account, nick);
+
+	if(!PURPLE_IS_CONTACT(contact)) {
+		contact = purple_contact_new(account, nick);
+		purple_contact_manager_add(manager, contact);
+	}
+
+	purple_contact_info_set_username(PURPLE_CONTACT_INFO(contact), nick);
+
+	return contact;
+}
diff --git a/libpurple/protocols/ircv3/purpleircv3messagehandlers.c b/libpurple/protocols/ircv3/purpleircv3messagehandlers.c
--- a/libpurple/protocols/ircv3/purpleircv3messagehandlers.c
+++ b/libpurple/protocols/ircv3/purpleircv3messagehandlers.c
@@ -123,10 +123,9 @@
                                      gpointer data)
 {
 	PurpleIRCv3Connection *connection = data;
-	PurpleAccount *account = NULL;
 	PurpleContact *contact = NULL;
-	PurpleContactManager *contact_manager = NULL;
 	PurpleConversation *conversation = NULL;
+	PurpleConversationMember *member = NULL;
 	PurpleMessage *message = NULL;
 	PurpleMessageFlags flags = PURPLE_MESSAGE_RECV;
 	GDateTime *dt = NULL;
@@ -162,26 +161,28 @@
 
 	purple_ircv3_source_parse(source, &nick, NULL, NULL);
 
-	account = purple_connection_get_account(PURPLE_CONNECTION(connection));
-
-	contact_manager = purple_contact_manager_get_default();
-	contact = purple_contact_manager_find_with_username(contact_manager,
-	                                                    account,
-	                                                    nick);
-	if(!PURPLE_IS_CONTACT(contact)) {
-		contact = purple_contact_new(account, NULL);
-		purple_contact_info_set_username(PURPLE_CONTACT_INFO(contact), nick);
-		purple_contact_info_set_sid(PURPLE_CONTACT_INFO(contact), source);
-		purple_contact_manager_add(contact_manager, contact);
-	}
-	g_clear_object(&contact);
-
+	/* Find or create the conversation. */
 	target = params[0];
 	if(!purple_ircv3_connection_is_channel(connection, target)) {
 		target = nick;
 	}
 	conversation = purple_ircv3_connection_find_or_create_conversation(connection,
 	                                                                   target);
+	/* Find or create the contact. */
+	contact = purple_ircv3_connection_find_or_create_contact(connection, nick);
+	if(PURPLE_IS_CONTACT(contact)) {
+		/* Update the contact's sid as it may have changed. */
+		purple_contact_info_set_sid(PURPLE_CONTACT_INFO(contact), source);
+
+		/* Make sure the contact is in the conversation. */
+		member = purple_conversation_find_member(conversation,
+		                                         PURPLE_CONTACT_INFO(contact));
+		if(!PURPLE_IS_CONVERSATION_MEMBER(member)) {
+			member = purple_conversation_add_member(conversation,
+			                                        PURPLE_CONTACT_INFO(contact),
+			                                        FALSE, NULL);
+		}
+	}
 
 	/* Grab the msgid if one was provided. */
 	if(g_hash_table_lookup_extended(tags, "msgid", NULL, &raw_id)) {
