Repository: getmoto/moto

Issue:
Bug: can't call SetIdentityMailFromDomain with Email address
Stack:

localstack 2.2.0 docker image
go 1.21.0
aws-sdk-go-v2

Code:

```
_, err = client.SetIdentityMailFromDomain(ctx, &ses.SetIdentityMailFromDomainInput{
	Identity:            aws.String("test@foo.com"),
	BehaviorOnMXFailure: types.BehaviorOnMXFailureUseDefaultValue,
	MailFromDomain:      aws.String("bar.foo.com"),
})
```

Got error response:
Provided MAIL-FROM domain 'bar.foo.com' is not subdomain of the domain of the identity 'test@foo.com'

Possible related code:
[https://github.com/getmoto/moto/blob/master/moto/ses/models.py#L582](https://github.com/getmoto/moto/blob/master/moto/ses/models.py#L582)

Expected:
Due to the official [document](https://docs.aws.amazon.com/ses/latest/APIReference/API_SetIdentityMailFromDomain.html), the Identity parameter could be Email address.


Discussion:
Thanks for raising this with us @luoxiaojun1992 - will open a PR with a fix shortly.

Welcome to Moto!

Resolving patch:
diff --git a/moto/ses/models.py b/moto/ses/models.py
--- a/moto/ses/models.py
+++ b/moto/ses/models.py
@@ -165,7 +165,7 @@ def _is_verified_address(self, source: str) -> bool:
             return True
         if address in self.email_addresses:
             return True
-        _, host = address.split("@", 1)
+        host = address.split("@", 1)[-1]
         return host in self.domains
 
     def verify_email_identity(self, address: str) -> None:
@@ -572,17 +572,17 @@ def set_identity_mail_from_domain(
         mail_from_domain: Optional[str] = None,
         behavior_on_mx_failure: Optional[str] = None,
     ) -> None:
-        if identity not in (self.domains + self.addresses):
+        if not self._is_verified_address(identity):
             raise InvalidParameterValue(f"Identity '{identity}' does not exist.")
 
         if mail_from_domain is None:
             self.identity_mail_from_domains.pop(identity)
             return
 
-        if not mail_from_domain.endswith(identity):
+        if not mail_from_domain.endswith(identity.split("@")[-1]):
             raise InvalidParameterValue(
                 f"Provided MAIL-FROM domain '{mail_from_domain}' is not subdomain of "
-                f"the domain of the identity '{identity}'."
+                f"the domain of the identity '{identity.split('@')[-1]}'."
             )
 
         if behavior_on_mx_failure not in (None, "RejectMessage", "UseDefaultValue"):


Test patch:
diff --git a/tests/test_ses/test_ses_boto3.py b/tests/test_ses/test_ses_boto3.py
--- a/tests/test_ses/test_ses_boto3.py
+++ b/tests/test_ses/test_ses_boto3.py
@@ -1472,6 +1472,22 @@ def test_set_identity_mail_from_domain():
     assert actual_attributes["BehaviorOnMXFailure"] == behaviour_on_mx_failure
     assert actual_attributes["MailFromDomainStatus"] == "Success"
 
+    # Can use email address as an identity
+    behaviour_on_mx_failure = "RejectMessage"
+    mail_from_domain = "lorem.foo.com"
+
+    conn.set_identity_mail_from_domain(
+        Identity="test@foo.com",
+        MailFromDomain=mail_from_domain,
+        BehaviorOnMXFailure=behaviour_on_mx_failure,
+    )
+
+    attributes = conn.get_identity_mail_from_domain_attributes(Identities=["foo.com"])
+    actual_attributes = attributes["MailFromDomainAttributes"]["foo.com"]
+    assert actual_attributes["MailFromDomain"] == mail_from_domain
+    assert actual_attributes["BehaviorOnMXFailure"] == behaviour_on_mx_failure
+    assert actual_attributes["MailFromDomainStatus"] == "Success"
+
     # Must unset config when MailFromDomain is null
     conn.set_identity_mail_from_domain(Identity="foo.com")