diff --git a/apimail/admin.py b/apimail/admin.py
index e7be3ceba704a0ff769a7c1a25c683dcd09b7687..9016f6a7e3a2193262423b08ad0a06c4db90e291 100644
--- a/apimail/admin.py
+++ b/apimail/admin.py
@@ -5,6 +5,7 @@ __license__ = "AGPL v3"
 from django.contrib import admin
 
 from .models import (
+    AddressBookEntry,
     Domain,
     EmailAccount, EmailAccountAccess,
     AttachmentFile,
@@ -76,7 +77,13 @@ class AddressValidationInline(admin.StackedInline):
     min_num = 0
 
 
+class AddressBookEntryInline(admin.StackedInline):
+    model = AddressBookEntry
+    extra = 0
+    min_num = 0
+
+
 class ValidatedAddressAdmin(admin.ModelAdmin):
-    inlines = [AddressValidationInline,]
+    inlines = [AddressValidationInline, AddressBookEntryInline,]
 
 admin.site.register(ValidatedAddress, ValidatedAddressAdmin)
diff --git a/apimail/api/serializers/__init__.py b/apimail/api/serializers/__init__.py
index 391f37d44581d74b3b352422f1299bffdc05869e..3101bfb7088376de6be78f8b6bfad92de0eaf4b9 100644
--- a/apimail/api/serializers/__init__.py
+++ b/apimail/api/serializers/__init__.py
@@ -16,3 +16,10 @@ from .composed_message import (
 )
 
 from .stored_message import StoredMessageSerializer
+
+from .validated_address import (
+    ValidatedAddressSerializer, AddressValidationSerializer,
+    ValidatedAddressSimpleSerializer
+)
+
+from .address_book import AddressBookEntrySerializer
diff --git a/apimail/api/serializers/address_book.py b/apimail/api/serializers/address_book.py
new file mode 100644
index 0000000000000000000000000000000000000000..d589a58d3ed1ab3d385562242ac47ca50b2f10fb
--- /dev/null
+++ b/apimail/api/serializers/address_book.py
@@ -0,0 +1,21 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from rest_framework import serializers
+
+from ...models import AddressBookEntry
+from ..serializers import ValidatedAddressSerializer
+
+
+class AddressBookEntrySerializer(serializers.ModelSerializer):
+    user = serializers.CharField()
+    address = ValidatedAddressSerializer()
+
+    class Meta:
+        model = AddressBookEntry
+        fields = ['pk', 'user', 'address', 'description']
+
+    def get_queryset(self):
+        user = self.context['request'].user
+        return AddressBookEntry.objects.filter(user=user)
diff --git a/apimail/api/serializers/validated_address.py b/apimail/api/serializers/validated_address.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7da63a9472a4e01ad8c20b82f58217e23cc089b
--- /dev/null
+++ b/apimail/api/serializers/validated_address.py
@@ -0,0 +1,37 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from rest_framework import serializers
+
+from ...models import ValidatedAddress, AddressValidation
+
+
+class AddressValidationSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = AddressValidation
+        fields = ['pk', 'data', 'datestamp']
+
+
+class ValidatedAddressSerializer(serializers.ModelSerializer):
+    validations = AddressValidationSerializer(many=True, read_only=True)
+
+    class Meta:
+        model = ValidatedAddress
+        fields = ['pk', 'address', 'validations']
+
+
+class ValidatedAddressSimpleSerializer(serializers.ModelSerializer):
+    address = serializers.CharField()
+    can_send = serializers.SerializerMethodField()
+    result = serializers.SerializerMethodField()
+
+    class Meta:
+        model = ValidatedAddress
+        fields = ['address', 'can_send', 'result']
+
+    def get_can_send(self, obj):
+        return obj.is_good_for_sending
+
+    def get_result(self, obj):
+        return obj.validations.first().data['result']
diff --git a/apimail/api/views/__init__.py b/apimail/api/views/__init__.py
index e14b3a275032bf0d06b744ae05edd80b9504a6ba..8d910bf00b4be542030daaa60a158e232d0ef9df 100644
--- a/apimail/api/views/__init__.py
+++ b/apimail/api/views/__init__.py
@@ -4,6 +4,8 @@ __license__ = "AGPL v3"
 
 from .account import EmailAccountListAPIView, UserEmailAccountAccessListAPIView
 
+from .address_book import check_address_book, AddressBookAPIView
+
 from .attachment import AttachmentFileCreateAPIView
 
 from .event import EventListAPIView, EventRetrieveAPIView
diff --git a/apimail/api/views/address_book.py b/apimail/api/views/address_book.py
new file mode 100644
index 0000000000000000000000000000000000000000..17823c164b75b35bf3224a1c1d9bf49111e2e00c
--- /dev/null
+++ b/apimail/api/views/address_book.py
@@ -0,0 +1,44 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from rest_framework.decorators import api_view, permission_classes
+from rest_framework.generics import ListAPIView
+from rest_framework.permissions import IsAuthenticated
+from rest_framework.response import Response
+from rest_framework import status
+from ...models import ValidatedAddress, AddressBookEntry
+from ..serializers import AddressBookEntrySerializer, ValidatedAddressSimpleSerializer
+
+
+@api_view(['POST'])
+@permission_classes([IsAuthenticated,])
+def check_address_book(request):
+    """
+    For a given email address in POST data, retrieve or create an AddressBookEntry.
+
+    The POST data must contain an 'email' entry.
+    """
+
+    if 'email' not in request.data.keys():
+        return Response(status=status.HTTP_400_BAD_REQUEST)
+
+    validated_address, address_created = ValidatedAddress.objects.get_or_create(
+        address=request.data['email'].lower()
+    )
+    validated_address.update_mailgun_validation()
+
+    entry, entry_created = AddressBookEntry.objects.get_or_create(
+        user=request.user,
+        address=validated_address,
+    )
+    serializer = ValidatedAddressSimpleSerializer(validated_address)
+    return Response(serializer.data)
+
+
+class AddressBookAPIView(ListAPIView):
+    permission_classes = (IsAuthenticated,)
+    serializer_class = AddressBookEntrySerializer
+
+    def get_queryset(self):
+        return self.request.user.address_book_entries.all()
diff --git a/apimail/migrations/0027_addressbookentry.py b/apimail/migrations/0027_addressbookentry.py
new file mode 100644
index 0000000000000000000000000000000000000000..453b3534512036d80b3c4225f199f58ee3820836
--- /dev/null
+++ b/apimail/migrations/0027_addressbookentry.py
@@ -0,0 +1,29 @@
+# Generated by Django 2.2.16 on 2020-10-25 13:12
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('apimail', '0026_addressvalidation_validatedaddress'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='AddressBookEntry',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('description', models.CharField(blank=True, help_text='Description: [last name], [first name] or [org name] or other', max_length=512)),
+                ('address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='address_book_entries', to='apimail.ValidatedAddress')),
+                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='address_book_entries', to=settings.AUTH_USER_MODEL)),
+            ],
+            options={
+                'verbose_name_plural': 'Address book entries',
+                'ordering': ['user', 'address'],
+            },
+        ),
+    ]
diff --git a/apimail/models/__init__.py b/apimail/models/__init__.py
index d4cc703bc356bf44abae880faadbfa4151c72479..7ed329eb1c4f449f9afd4c3adedd6781052890ef 100644
--- a/apimail/models/__init__.py
+++ b/apimail/models/__init__.py
@@ -4,6 +4,8 @@ __license__ = "AGPL v3"
 
 from .account import EmailAccount, EmailAccountAccess
 
+from .address_book import AddressBookEntry
+
 from .attachment import AttachmentFile
 
 from .composed_message import ComposedMessage, ComposedMessageAPIResponse
diff --git a/apimail/models/address_book.py b/apimail/models/address_book.py
new file mode 100644
index 0000000000000000000000000000000000000000..695badb316f876ebcde6ef3d8ef3784cb90fc906
--- /dev/null
+++ b/apimail/models/address_book.py
@@ -0,0 +1,37 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.conf import settings
+from django.db import models
+
+
+class AddressBookEntry(models.Model):
+    """
+    Through field relating User and ValidatedAddress.
+    """
+
+    user = models.ForeignKey(
+        settings.AUTH_USER_MODEL,
+        on_delete=models.CASCADE,
+        related_name='address_book_entries'
+    )
+
+    address = models.ForeignKey(
+        'apimail.ValidatedAddress',
+        on_delete=models.CASCADE,
+        related_name='address_book_entries'
+    )
+
+    description = models.CharField(
+        max_length=512,
+        blank=True,
+        help_text='Description: [last name], [first name] or [org name] or other'
+    )
+
+    class Meta:
+        ordering = [
+            'user',
+            'address'
+        ]
+        verbose_name_plural = 'Address book entries'
diff --git a/apimail/static/apimail/assets/vue/components/MessageComposer.vue b/apimail/static/apimail/assets/vue/components/MessageComposer.vue
index 0cc5f8b7a2d55ad99c2031870d6bcd77917253b4..485dc52f24a1b4359f29acf92d55360a09ff992f 100644
--- a/apimail/static/apimail/assets/vue/components/MessageComposer.vue
+++ b/apimail/static/apimail/assets/vue/components/MessageComposer.vue
@@ -10,10 +10,31 @@
       >
       Save draft
     </b-button>
+    <span v-if="!allEmailsValid">
+      <b-button
+	type="validateemails"
+	class="text-white px-2 py-1 my-2"
+	variant="warning"
+	@click.stop.prevent="validateAllEmails()"
+	:disabled="emailValidationHasRun || (!form.to_recipient && form.cc_recipients.length == 0 && form.bcc_recipients == 0)"
+	>
+	Validate emails
+      </b-button>
+    </span>
+    <span v-else>
+      <b-button
+	type="validateemails"
+	class="text-white px-2 py-1 my-2"
+	variant="success"
+	>
+	All emails are validated
+      </b-button>
+    </span>
     <b-button
       type="send"
       class="text-white px-2 py-1 my-2"
       variant="primary"
+      :disabled="!emailValidationHasRun || !allEmailsValid"
       @click.stop.prevent="saveMessage('ready')"
       >
       Send
@@ -42,6 +63,15 @@
     </div>
   </template>
   <span v-if="draftLastSaved" size="sm">&emsp;[last saved: {{ draftLastSaved }}]</span>
+  <template v-if="emailValidationHasRun && !allEmailsValid">
+    <p class="m-2 p-2">
+      <strong class="text-danger">Some email addresses cannot be sent to:</strong>
+      <ul class="mb-0">
+	<li v-for="item in emailValidations">{{ item.address }}&emsp;<span v-if="item.can_send" class="text-success">Can send</span><span v-else><strong class="text-danger">Cannot send: {{ item.result }}</strong></span></li>
+      </ul>
+      <strong class="text-danger">Please remove the failing addresses from your message draft.</strong>
+    </p>
+  </template>
   <b-form>
     <b-row>
       <b-col class="col-lg-6">
@@ -332,6 +362,9 @@ export default {
 		headers_added: {},
 		attachments: [],
 	    },
+	    emailValidations: [],
+	    emailValidationHasRun: false,
+	    allEmailsValid: false,
 	    from_account_accesses: [],
 	    response: null,
 	    response_body_json: null,
@@ -434,6 +467,29 @@ export default {
 		    this.currentdraft_uuid = responsejson.uuid
 		})
 		.catch(error => console.error(error))
+	},
+	verifyEmailValidity (email) {
+	    fetch('/mail/api/check_address_book',
+	    	  {
+	    	      method: 'POST',
+	    	      headers: {
+	    		  "X-CSRFToken": csrftoken,
+	    		  "Content-Type": "application/json; charset=utf-8"
+	    	      },
+	    	      body: JSON.stringify({
+	    		  'email': email
+	    	      })
+		  })
+		.then(response => response.json())
+		.then(responsejson => this.emailValidations.push(responsejson))
+		.catch(error => console.error(error))
+	},
+	validateAllEmails () {
+	    this.emailValidations = []
+	    if (this.form.to_recipient) this.verifyEmailValidity(this.form.to_recipient)
+	    this.form.cc_recipients.forEach(email => this.verifyEmailValidity(email))
+	    this.form.bcc_recipients.forEach(email => this.verifyEmailValidity(email))
+	    this.emailValidationHasRun = true
 	}
     },
     mounted () {
@@ -495,6 +551,26 @@ export default {
 	}
 	this.editor.setContent(this.form.body_html)
     },
+    watch: {
+	"form.to_recipient": function () {
+	    this.emailValidationHasRun = false
+	    this.allEmailsValid = false
+	},
+	"form.cc_recipients": function () {
+	    this.emailValidationHasRun = false
+	    this.allEmailsValid = false
+	},
+	"form.bcc_recipients": function () {
+	    this.emailValidationHasRun = false
+	    this.allEmailsValid = false
+	},
+	emailValidations: function () {
+	    this.allEmailsValid = true
+	    this.emailValidations.forEach(item => {
+		if (!item.can_send) this.allEmailsValid = false
+	    })
+	}
+    },
     beforeDestroy() {
 	this.editor.destroy()
     },
diff --git a/apimail/static/apimail/assets/vue/components/MessagesTable.vue b/apimail/static/apimail/assets/vue/components/MessagesTable.vue
index 00eeea8d29240ad1d72a6d1d3a3a64f9889797c2..489890ddb972f3e16c61f2ba681963bcf78dbac0 100644
--- a/apimail/static/apimail/assets/vue/components/MessagesTable.vue
+++ b/apimail/static/apimail/assets/vue/components/MessagesTable.vue
@@ -572,6 +572,8 @@ export default {
 	    return false
 	},
 	messagesProvider (ctx) {
+	    if (!this.accountSelected) return []
+
 	    var params = '?account=' + this.accountSelected.email
 	    // Our API uses limit/offset pagination
 	    params += '&limit=' + ctx.perPage + '&offset=' + ctx.perPage * (ctx.currentPage - 1)
@@ -612,11 +614,11 @@ export default {
 		    this.totalRows = data.count
 		    if (this.threadOf) {
 			this.tabbedMessages = items
-		    }
-		    return items || []
+			}
+			return items || []
 		})
-	},
-	refreshMessages () {
+	    },
+	    refreshMessages () {
 	    this.messagesProvider({
 		'perPage': this.perPage,
 		'currentPage': this.currentPage
diff --git a/apimail/urls.py b/apimail/urls.py
index e87725aece0a0c040866c157f4c9563424b7aba9..32f087d415a39c54ab8716fa3d6fce495f2b66b6 100644
--- a/apimail/urls.py
+++ b/apimail/urls.py
@@ -97,6 +97,16 @@ urlpatterns = [
             apiviews.UserTagListAPIView.as_view(),
             name='api_user_tags'
         ),
+        path( # /mail/api/address_book
+            'address_book',
+            apiviews.AddressBookAPIView.as_view(),
+            name='api_address_book'
+        ),
+        path( # /mail/api/check_address_book
+            'check_address_book',
+            apiviews.check_address_book,
+            name='api_check_address_book'
+        ),
     ])),