diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json
index ef14baaa3ed4aca5c3f726bc1133a6c4b3b4edb1..f2db99b3e41d6666475f21fe6bef912f9eb59081 100644
--- a/frontend/public/locales/en/common.json
+++ b/frontend/public/locales/en/common.json
@@ -95,7 +95,8 @@
     "cancel": "Cancel",
     "backToFrontPage": "Go to front page",
     "cancelInvitation": "Cancel",
-    "resendInvitation": "Send"
+    "resendInvitation": "Send",
+    "ok": "OK"
   },
   "registerWizardText": {
     "registerPage": "Enter the contact information for the guest below. All fields are mandatory.",
@@ -123,5 +124,8 @@
   "feideId": "Feide ID",
   "thankYou": "Thanks!",
   "sponsorSubmitSuccessDescription": "Your registration has been completed. You will receive an e-mail when the guest has filled in the missing information, so that the guest account can be approved.",
-  "guestSubmitSuccessDescription": "Your registration is now completed. You will receive an e-mail or SMS when your account has been created."
+  "guestSubmitSuccessDescription": "Your registration is now completed. You will receive an e-mail or SMS when your account has been created.",
+  "confirmationDialog": {
+    "cancelInvitation": "Cancel invitation?"
+  }
 }
diff --git a/frontend/public/locales/nb/common.json b/frontend/public/locales/nb/common.json
index 6efe20b73ec0688178da2771fa05857e50da8b1f..df018736e3c62f01d1915de10984960011d88f76 100644
--- a/frontend/public/locales/nb/common.json
+++ b/frontend/public/locales/nb/common.json
@@ -95,7 +95,8 @@
     "cancel": "Avbryt",
     "backToFrontPage": "Tilbake til forsiden",
     "resendInvitation": "Send",
-    "cancelInvitation": "Kanseller"
+    "cancelInvitation": "Kanseller",
+    "ok": "OK"
   },
   "registerWizardText": {
     "registerPage": "Fyll inn kontaktinformasjonen til gjesten under. Alle feltene er obligatoriske.",
@@ -123,5 +124,8 @@
   "feideId": "Feide ID",
   "thankYou": "Takk!",
   "sponsorSubmitSuccessDescription": "Din registrering er nå fullført. Du vil få en e-post når gjesten har fylt inn informasjonen som mangler, slik at gjestekontoen kan godkjennes.",
-  "guestSubmitSuccessDescription": "Din registrering er nå fullført. Du vil få en e-post eller SMS når kontoen er opprettet."
+  "guestSubmitSuccessDescription": "Din registrering er nå fullført. Du vil få en e-post eller SMS når kontoen er opprettet.",
+  "confirmationDialog": {
+    "cancelInvitation": "Kanseller invitasjon?"
+  }
 }
diff --git a/frontend/public/locales/nn/common.json b/frontend/public/locales/nn/common.json
index f7bd06aa336fbf4bcb50ed7918e03e681dad706d..7b6f41b69889cfb5e74c169ee34a8887e4b4d99f 100644
--- a/frontend/public/locales/nn/common.json
+++ b/frontend/public/locales/nn/common.json
@@ -96,7 +96,8 @@
     "cancel": "Avbryt",
     "backToFrontPage": "Tilbake til forsida",
     "resendInvitation": "Send",
-    "cancelInvitation": "Kanseller"
+    "cancelInvitation": "Kanseller",
+    "ok": "OK"
   },
   "registerWizardText": {
     "registerPage": "Fyll inn kontaktinformasjonen til gjesten under. Alle feltene er obligatoriske.",
@@ -124,5 +125,8 @@
   "feideId": "Feide ID",
   "thankYou": "Takk!",
   "sponsorSubmitSuccessDescription": "Di registrering er no fullført. Du vil få ein e-post når gjesten har fylt inn informasjonen som manglar, slik at gjestekontoen kan godkjennast.",
-  "guestSubmitSuccessDescription": "Di registrering er no fullført. Du vil få ein e-post eller SMS når kontoen er oppretta."
+  "guestSubmitSuccessDescription": "Di registrering er no fullført. Du vil få ein e-post eller SMS når kontoen er oppretta.",
+  "confirmationDialog": {
+    "cancelInvitation": "Kanseller invitasjon?"
+  }
 }
diff --git a/gregui/api/serializers/guest.py b/gregui/api/serializers/guest.py
index ce702752a1b1d0613bd339a1d34e965a8909290b..6387d938f59854ec769a969139bd74fd5a89343d 100644
--- a/gregui/api/serializers/guest.py
+++ b/gregui/api/serializers/guest.py
@@ -1,20 +1,7 @@
-import phonenumbers
 from rest_framework import serializers
 
 from greg.models import Identity, Person
-from greg.utils import is_valid_norwegian_national_id_number
-
-
-def _validateNorwegianNationalIdNumber(value):
-    # Not excepted that D-numbers will be entered through the form, so only
-    # accept national ID numbers
-    if not is_valid_norwegian_national_id_number(value, False):
-        raise serializers.ValidationError("Not a valid Norwegian national ID number")
-
-
-def _validatePhoneNumber(value):
-    if not phonenumbers.is_valid_number(phonenumbers.parse(value)):
-        raise serializers.ValidationError("Invalid phone number")
+from gregui.validation import validate_phone_number, validate_norwegian_national_id_number
 
 
 class GuestRegisterSerializer(serializers.ModelSerializer):
@@ -25,10 +12,10 @@ class GuestRegisterSerializer(serializers.ModelSerializer):
     # the guest should be allowed to update it
     email = serializers.CharField(required=False)
     mobile_phone = serializers.CharField(
-        required=True, validators=[_validatePhoneNumber]
+        required=True, validators=[validate_phone_number]
     )
     fnr = serializers.CharField(
-        required=False, validators=[_validateNorwegianNationalIdNumber]
+        required=False, validators=[validate_norwegian_national_id_number]
     )
 
     def update(self, instance, validated_data):
@@ -36,40 +23,14 @@ class GuestRegisterSerializer(serializers.ModelSerializer):
 
         if "email" in validated_data:
             email = validated_data.pop("email")
-            if not instance.private_email:
-                Identity.objects.create(
-                    person=instance,
-                    type=Identity.IdentityType.PRIVATE_EMAIL,
-                    value=email,
-                )
-            else:
-                private_email = instance.private_email
-                private_email.value = email
-                private_email.save()
+            create_identity_or_update(Identity.IdentityType.PRIVATE_EMAIL, email, instance)
 
         if not instance.private_mobile:
-            Identity.objects.create(
-                person=instance,
-                type=Identity.IdentityType.PRIVATE_MOBILE_NUMBER,
-                value=mobile_phone,
-            )
-        else:
-            private_mobile = instance.private_mobile
-            private_mobile.value = mobile_phone
-            private_mobile.save()
+            create_identity_or_update(Identity.IdentityType.PRIVATE_MOBILE_NUMBER, mobile_phone, instance)
 
         if "fnr" in validated_data:
             fnr = validated_data.pop("fnr")
-            if not instance.fnr:
-                Identity.objects.create(
-                    person=instance,
-                    type=Identity.IdentityType.NORWEGIAN_NATIONAL_ID_NUMBER,
-                    value=fnr,
-                )
-            else:
-                fnr_existing = instance.fnr
-                fnr_existing.value = fnr
-                fnr_existing.save()
+            create_identity_or_update(Identity.IdentityType.NORWEGIAN_NATIONAL_ID_NUMBER, fnr, instance)
 
         # TODO: we only want to allow changing the name if we don't have one
         #       from a reliable source (Feide/KORR)
@@ -83,3 +44,16 @@ class GuestRegisterSerializer(serializers.ModelSerializer):
         model = Person
         fields = ("id", "first_name", "last_name", "email", "mobile_phone", "fnr")
         read_only_fields = ("id",)
+
+
+def create_identity_or_update(identity_type: Identity.IdentityType, value: str, person: Person):
+    existing_identity = person.identities.filter(type=identity_type).first()
+    if not existing_identity:
+        Identity.objects.create(
+            person=person,
+            type=identity_type,
+            value=value,
+        )
+    else:
+        existing_identity.value = value
+        existing_identity.save()
diff --git a/gregui/api/views/invitation.py b/gregui/api/views/invitation.py
index 4bc40f27ec416ea5db59913d443809ae1fbf4faf..7f139d576c7925bd35716d82fc0969ef97b1cc94 100644
--- a/gregui/api/views/invitation.py
+++ b/gregui/api/views/invitation.py
@@ -73,11 +73,12 @@ class InvitationView(CreateAPIView, DestroyAPIView):
         serializer.is_valid(raise_exception=True)
         person = serializer.save()
 
-        invitationlink = InvitationLink.objects.filter(
-            invitation__role__person_id=person.id,
-            invitation__role__sponsor_id=sponsor_user.sponsor.id,
-        )
-        send_invite_mail(invitationlink)
+        for invitationlink in InvitationLink.objects.filter(
+                invitation__role__person_id=person.id,
+                invitation__role__sponsor_id=sponsor_user.sponsor_id,
+        ):
+            send_invite_mail(invitationlink)
+
         return Response(status=status.HTTP_201_CREATED)
 
     def delete(self, request, *args, **kwargs) -> Response:
diff --git a/gregui/validation.py b/gregui/validation.py
new file mode 100644
index 0000000000000000000000000000000000000000..7da189d8804e4deff179693f1945d77bcb6ef4b9
--- /dev/null
+++ b/gregui/validation.py
@@ -0,0 +1,24 @@
+import re
+import phonenumbers
+from rest_framework import serializers
+
+from greg.utils import is_valid_norwegian_national_id_number
+
+_valid_email_regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
+
+
+def validate_norwegian_national_id_number(value):
+    # Not excepted that D-numbers will be entered through the form, so only
+    # accept national ID numbers
+    if not is_valid_norwegian_national_id_number(value, False):
+        raise serializers.ValidationError("Not a valid Norwegian national ID number")
+
+
+def validate_phone_number(value):
+    if not phonenumbers.is_valid_number(phonenumbers.parse(value)):
+        raise serializers.ValidationError("Invalid phone number")
+
+
+def validate_email(value):
+    if not re.fullmatch(_valid_email_regex, value):
+        raise serializers.ValidationError("Invalid e-mail")