diff --git a/SignalMessaging/profiles/ProfileFetcherJob.swift b/SignalMessaging/profiles/ProfileFetcherJob.swift
index acd4c8afc..4810f7517 100644
--- a/SignalMessaging/profiles/ProfileFetcherJob.swift
+++ b/SignalMessaging/profiles/ProfileFetcherJob.swift
@@ -180,29 +180,34 @@ public class ProfileFetcherJob: NSObject {
                                      profileNameEncrypted: signalServiceProfile.profileNameEncrypted,
                                      avatarUrlPath: signalServiceProfile.avatarUrlPath)
 
-        // Recipients should be in "UD delivery mode" IFF:
-        //
-        // * Their profile includes a unidentifiedAccessVerifier.
-        // * The unidentifiedAccessVerifier matches the "expected" value derived
-        //   from their profile key (if any).
-        //
-        // Recipients should be in "normal delivery mode" otherwise.
-        var supportsUnidentifiedDelivery = false
-        if let unidentifiedAccessVerifier = signalServiceProfile.unidentifiedAccessVerifier,
-            let udAccessKey = udManager.udAccessKeyForRecipient(recipientId) {
-            let dataToVerify = Data(count: 32)
-            if let expectedVerfier = Cryptography.computeSHA256HMAC(dataToVerify, withHMACKey: udAccessKey.keyData) {
-                supportsUnidentifiedDelivery = expectedVerfier == unidentifiedAccessVerifier
-            } else {
-                owsFailDebug("could not verify UD")
-            }
+        updateUnidentifiedAccess(recipientId: recipientId, verifier: signalServiceProfile.unidentifiedAccessVerifier, hasUnrestrictedAccess: signalServiceProfile.hasUnrestrictedUnidentifiedAccess)
+    }
+
+    private func updateUnidentifiedAccess(recipientId: String, verifier: Data?, hasUnrestrictedAccess: Bool) {
+        if hasUnrestrictedAccess {
+            udManager.setUnidentifiedAccessMode(.unrestricted, recipientId: recipientId)
+            return
         }
 
-        // TODO: We may want to only call setSupportsUnidentifiedDelivery if
-        // supportsUnidentifiedDelivery is true.
-        udManager.setSupportsUnidentifiedDelivery(supportsUnidentifiedDelivery, recipientId: recipientId)
+        guard let verifier = verifier, let udAccessKey = udManager.udAccessKeyForRecipient(recipientId) else {
+            udManager.setUnidentifiedAccessMode(.disabled, recipientId: recipientId)
+            return
+        }
+
+        let dataToVerify = Data(count: 32)
+        guard let expectedVerfier = Cryptography.computeSHA256HMAC(dataToVerify, withHMACKey: udAccessKey.keyData) else {
+            owsFailDebug("could not compute verification")
+            udManager.setUnidentifiedAccessMode(.disabled, recipientId: recipientId)
+            return
+        }
+
+        guard expectedVerfier == verifier else {
+            Logger.verbose("verifier mismatch, new profile key?")
+            udManager.setUnidentifiedAccessMode(.disabled, recipientId: recipientId)
+            return
+        }
 
-        udManager.setShouldAllowUnrestrictedAccess(recipientId: recipientId, shouldAllowUnrestrictedAccess: signalServiceProfile.hasUnrestrictedUnidentifiedAccess)
+        udManager.setUnidentifiedAccessMode(.enabled, recipientId: recipientId)
     }
 
     private func verifyIdentityUpToDateAsync(recipientId: String, latestIdentityKey: Data) {
diff --git a/SignalServiceKit/src/Messages/OWSMessageSend.swift b/SignalServiceKit/src/Messages/OWSMessageSend.swift
index 7918ff904..4a693e8a2 100644
--- a/SignalServiceKit/src/Messages/OWSMessageSend.swift
+++ b/SignalServiceKit/src/Messages/OWSMessageSend.swift
@@ -70,9 +70,14 @@ public class OWSMessageSend: NSObject {
         var udAccessKey: SMKUDAccessKey?
         var isLocalNumber: Bool = false
         if let recipientId = recipient.uniqueId {
-            udAccessKey = (udManager.supportsUnidentifiedDelivery(recipientId: recipientId)
-                ? udManager.udAccessKeyForRecipient(recipientId)
-                : nil)
+            switch udManager.unidentifiedAccessMode(recipientId: recipientId) {
+            case .enabled:
+                udAccessKey = udManager.udAccessKeyForRecipient(recipientId)
+            case .unrestricted:
+                udAccessKey = udManager.generateAccessKeyForUnrestrictedRecipient()
+            case .disabled, .unknown:
+                udAccessKey = nil
+            }
             isLocalNumber = localNumber == recipientId
         } else {
             owsFailDebug("SignalRecipient missing recipientId")
diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m
index d091dc94d..7cdda4190 100644
--- a/SignalServiceKit/src/Messages/OWSMessageSender.m
+++ b/SignalServiceKit/src/Messages/OWSMessageSender.m
@@ -1041,7 +1041,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
                     //
                     // TODO: Do we want to discriminate based on exact error?
                     OWSLogDebug(@"UD send failed; failing over to non-UD send.");
-                    [self.udManager setSupportsUnidentifiedDelivery:NO recipientId:recipient.uniqueId];
+                    [self.udManager setUnidentifiedAccessMode:UnidentifiedAccessModeDisabled
+                                                  recipientId:recipient.uniqueId];
                     messageSend.hasUDAuthFailed = YES;
                     dispatch_async([OWSDispatch sendingQueue], ^{
                         [self sendMessageToRecipient:messageSend];
diff --git a/SignalServiceKit/src/Messages/UD/OWSUDManager.swift b/SignalServiceKit/src/Messages/UD/OWSUDManager.swift
index 0c4022eed..ee5758e3c 100644
--- a/SignalServiceKit/src/Messages/UD/OWSUDManager.swift
+++ b/SignalServiceKit/src/Messages/UD/OWSUDManager.swift
@@ -12,38 +12,47 @@ public enum OWSUDError: Error {
     case invalidData(description: String)
 }
 
+@objc
+public enum UnidentifiedAccessMode: Int {
+    case unknown
+    case enabled
+    case disabled
+    case unrestricted
+}
+
 @objc public protocol OWSUDManager: class {
 
     @objc func setup()
 
     @objc func trustRoot() -> ECPublicKey
 
-    // MARK: - Recipient state
+    // MARK: - Recipient State
 
-    @objc func supportsUnidentifiedDelivery(recipientId: String) -> Bool
+    @objc
+    func unidentifiedAccessMode(recipientId: String) -> UnidentifiedAccessMode
 
-    @objc func setSupportsUnidentifiedDelivery(_ value: Bool, recipientId: String)
+    @objc
+    func setUnidentifiedAccessMode(_ mode: UnidentifiedAccessMode, recipientId: String)
 
     // Returns the UD access key for a given recipient if they are
     // a UD recipient and we have a valid profile key for them.
     @objc func udAccessKeyForRecipient(_ recipientId: String) -> SMKUDAccessKey?
 
-    // MARK: - Sender Certificate
+    @objc
+    func generateAccessKeyForUnrestrictedRecipient() -> SMKUDAccessKey
+    // MARK: - Local State
+
+    // MARK: Sender Certificate
 
     // We use completion handlers instead of a promise so that message sending
-    // logic can access the certificate data.
+    // logic can access the strongly typed certificate data.
     @objc func ensureSenderCertificateObjC(success:@escaping (SMKSenderCertificate) -> Void,
                                             failure:@escaping (Error) -> Void)
 
-    // MARK: - Unrestricted Access
+    // MARK: Unrestricted Access
 
     @objc func shouldAllowUnrestrictedAccessLocal() -> Bool
-
     @objc func setShouldAllowUnrestrictedAccessLocal(_ value: Bool)
-
-    @objc func shouldAllowUnrestrictedAccess(recipientId: String) -> Bool
-
-    @objc func setShouldAllowUnrestrictedAccess(recipientId: String, shouldAllowUnrestrictedAccess: Bool)
 }
 
 // MARK: -
@@ -53,11 +62,13 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
 
     private let dbConnection: YapDatabaseConnection
 
+    // MARK: Local Configuration State
     private let kUDCollection = "kUDCollection"
     private let kUDCurrentSenderCertificateKey = "kUDCurrentSenderCertificateKey"
     private let kUDUnrestrictedAccessKey = "kUDUnrestrictedAccessKey"
-    private let kUDRecipientModeCollection = "kUDRecipientModeCollection"
-    private let kUDUnrestrictedAccessCollection = "kUDUnrestrictedAccessCollection"
+
+    // MARK: Recipient State
+    private let kUnidentifiedAccessCollection = "kUnidentifiedAccessCollection"
 
     @objc
     public required init(primaryStorage: OWSPrimaryStorage) {
@@ -101,20 +112,24 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
     // MARK: - Recipient state
 
     @objc
-    public func supportsUnidentifiedDelivery(recipientId: String) -> Bool {
+    public func unidentifiedAccessMode(recipientId: String) -> UnidentifiedAccessMode {
         if tsAccountManager.localNumber() == recipientId {
-            return true
+            if shouldAllowUnrestrictedAccessLocal() {
+                return .unrestricted
+            } else {
+                return .enabled
+            }
+        }
+
+        guard let existingValue = dbConnection.object(forKey: recipientId, inCollection: kUnidentifiedAccessCollection) as? UnidentifiedAccessMode else {
+            return .unknown
         }
-        return dbConnection.bool(forKey: recipientId, inCollection: kUDRecipientModeCollection, defaultValue: false)
+        return existingValue
     }
 
     @objc
-    public func setSupportsUnidentifiedDelivery(_ value: Bool, recipientId: String) {
-        if value {
-            dbConnection.setBool(true, forKey: recipientId, inCollection: kUDRecipientModeCollection)
-        } else {
-            dbConnection.removeObject(forKey: recipientId, inCollection: kUDRecipientModeCollection)
-        }
+    public func setUnidentifiedAccessMode(_ mode: UnidentifiedAccessMode, recipientId: String) {
+        dbConnection.setObject(mode, forKey: recipientId, inCollection: kUnidentifiedAccessCollection)
     }
 
     // Returns the UD access key for a given recipient
@@ -134,6 +149,11 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
         }
     }
 
+    @objc
+    public func generateAccessKeyForUnrestrictedRecipient() -> SMKUDAccessKey {
+        return SMKUDAccessKey(randomKeyData: ())
+    }
+
     // MARK: - Sender Certificate
 
     #if DEBUG
@@ -251,14 +271,4 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
     public func setShouldAllowUnrestrictedAccessLocal(_ value: Bool) {
         dbConnection.setBool(value, forKey: kUDUnrestrictedAccessKey, inCollection: kUDCollection)
     }
-
-    @objc
-    public func shouldAllowUnrestrictedAccess(recipientId: String) -> Bool {
-        return dbConnection.bool(forKey: recipientId, inCollection: kUDUnrestrictedAccessCollection, defaultValue: false)
-    }
-
-    @objc
-    public func setShouldAllowUnrestrictedAccess(recipientId: String, shouldAllowUnrestrictedAccess: Bool) {
-        dbConnection.setBool(shouldAllowUnrestrictedAccess, forKey: recipientId, inCollection: kUDUnrestrictedAccessCollection)
-    }
 }