Поделиться через


Настраиваемая проверка электронной почты с помощью SendGrid

Прежде чем начать, используйте селектор типа политики в верхней части этой страницы, чтобы выбрать тип политики, которую вы настроите. Azure Active Directory B2C предлагает два метода определения способа взаимодействия пользователей с вашими приложениями: с помощью предопределенных потоков пользователей или полностью настраиваемых пользовательских политик. Действия, которые необходимо выполнить, отличаются для каждого метода.

Используйте настраиваемую электронную почту в Azure Active Directory B2C (Azure AD B2C) для отправки настраиваемой электронной почты пользователям, которые регистрируются для использования приложений. Используя стороннего поставщика услуг электронной почты SendGrid, вы можете применять собственный шаблон электронной почты и адрес отправителя с темой, поддерживать локализацию, а также настраивать пользовательские параметры одноразового пароля (OTP).

Эта функция доступна только для пользовательских политик. Для действий по настройке выберите пользовательскую политику в предыдущем селекторе.

Для проверки пользовательской почты требуется использование стороннего поставщика электронной почты, например SendGrid, Mailjet или SparkPost, пользовательского REST API или любого поставщика электронной почты на основе HTTP (включая собственный). В этой статье описывается настройка решения, использующего SendGrid.

Создание учетной записи SendGrid

Если у вас еще нет учетной записи SendGrid, начните с настройки учетной записи SendGrid. Инструкции по настройке см. в разделе Создание учетной записи SendGrid статьи Отправка электронной почты с использованием SendGrid в Azure.

Убедитесь, что вы завершите работу с разделом, в котором создается ключ API SendGrid. Запишите ключ API для использования на следующем шаге.

Это важно

SendGrid предлагает клиентам возможность отправлять сообщения электронной почты из общего IP-адреса и выделенных IP-адресов. При использовании выделенных IP-адресов необходимо правильно создать собственную репутацию с помощью прогрева IP-адреса. Дополнительные сведения см. в разделе "Прогревание IP-адреса".

Создание ключа политики Azure AD B2C

Затем сохраните ключ API SendGrid в ключе политики Azure AD B2C, чтобы ваши политики могли на него ссылаться.

  1. Войдите на портал Azure.
  2. Если у вас есть доступ к нескольким клиентам, щелкните значок Настройки в верхнем меню, чтобы переключиться на клиент Azure AD B2C из меню Каталоги и подписки.
  3. В левом верхнем углу портала Azure выберите все службы, а затем найдите и выберите Azure AD B2C.
  4. На странице обзора выберите Identity Experience Framework.
  5. Выберите ключи политики и нажмите кнопку "Добавить".
  6. Для Параметры выберите Ручной.
  7. Введите имя для ключа политики. Например, SendGridSecret. Префикс B2C_1A_ добавляется автоматически в имя ключа.
  8. В поле Secret введите ранее записанный ключ API SendGrid.
  9. Для назначения ключа выберите Подпись.
  10. Выберите Создать.

Создание шаблона SendGrid

С помощью созданной учетной записи SendGrid и ключа API SendGrid, хранящегося в ключе политики Azure AD B2C, создайте шаблон динамической транзакции SendGrid.

  1. На сайте SendGrid откройте страницу шаблонов транзакций и выберите "Создать динамический шаблон".

  2. Введите уникальное имя шаблона, например Verification email , и нажмите кнопку "Создать".

  3. Чтобы начать редактирование нового шаблона, выберите шаблон, Verification emailкоторый есть, а затем нажмите кнопку "Добавить версию".

  4. Выберите пустой шаблон и редактор кода.

  5. В редакторе HTML вставьте следующий шаблон HTML или используйте собственный. Параметры {{otp}} и {{email}} динамически заменяются значением одноразового пароля и адресом электронной почты пользователя.

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en"><head id="Head1">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Contoso demo account email verification code</title><meta name="ROBOTS" content="NOINDEX, NOFOLLOW">
       <style>
           table td {border-collapse:collapse;margin:0;padding:0;}
       </style>
    </head>
    <body dir="ltr" lang="en">
       <table width="100%" cellpadding="0" cellspacing="0" border="0" dir="ltr" lang="en">
            <tr>
               <td valign="top" width="50%"></td>
               <td valign="top">
                  <!-- Email Header -->
                  <table width="640" cellpadding="0" cellspacing="0" border="0" dir="ltr" lang="en" style="border-left:1px solid #e3e3e3;border-right: 1px solid #e3e3e3;">
                   <tr style="background-color: #0072C6;">
                       <td width="1" style="background:#0072C6; border-top:1px solid #e3e3e3;"></td>
                       <td width="24" style="border-top:1px solid #e3e3e3;border-bottom:1px solid #e3e3e3;">&nbsp;</td>
                       <td width="310" valign="middle" style="border-top:1px solid #e3e3e3; border-bottom:1px solid #e3e3e3;padding:12px 0;">
                           <h1 style="line-height:20pt;font-family:Segoe UI Light; font-size:18pt; color:#ffffff; font-weight:normal;">
                            <span id="HeaderPlaceholder_UserVerificationEmailHeader"><font color="#FFFFFF">Verify your email address</font></span>
                           </h1>
                       </td>
                       <td width="24" style="border-top: 1px solid #e3e3e3;border-bottom: 1px solid #e3e3e3;">&nbsp;</td>
                   </tr>
                  </table>
                  <!-- Email Content -->
                  <table width="640" cellpadding="0" cellspacing="0" border="0" dir="ltr" lang="en">
                   <tr>
                       <td width="1" style="background:#e3e3e3;"></td>
                       <td width="24">&nbsp;</td>
                       <td id="PageBody" width="640" valign="top" colspan="2" style="border-bottom:1px solid #e3e3e3;padding:10px 0 20px;border-bottom-style:hidden;">
                           <table cellpadding="0" cellspacing="0" border="0">
                               <tr>
                                   <td width="630" style="font-size:10pt; line-height:13pt; color:#000;">
                                       <table cellpadding="0" cellspacing="0" border="0" width="100%" style="" dir="ltr" lang="en">
                                           <tr>
                                               <td>
    
       <div style="font-family:'Segoe UI', Tahoma, sans-serif; font-size:14px; color:#333;">
           <span id="BodyPlaceholder_UserVerificationEmailBodySentence1">Thanks for verifying your {{email}} account!</span>
       </div>
       <br>
       <div style="font-family:'Segoe UI', Tahoma, sans-serif; font-size:14px; color:#333; font-weight: bold">
           <span id="BodyPlaceholder_UserVerificationEmailBodySentence2">Your code is: {{otp}}</span>
       </div>
       <br>
       <br>
    
                                                   <div style="font-family:'Segoe UI', Tahoma, sans-serif; font-size:14px; color:#333;">
                                                   Sincerely,
                                                   </div>
                                                   <div style="font-family:'Segoe UI', Tahoma, sans-serif; font-size:14px; font-style:italic; color:#333;">
                                                       Contoso
                                                   </div>
                                               </td>
                                           </tr>
                                       </table>
                                   </td>
                               </tr>
                           </table>
    
                       </td>
    
                       <td width="1">&nbsp;</td>
                       <td width="1"></td>
                       <td width="1">&nbsp;</td>
                       <td width="1" valign="top"></td>
                       <td width="29">&nbsp;</td>
                       <td width="1" style="background:#e3e3e3;"></td>
                   </tr>
                   <tr>
                       <td width="1" style="background:#e3e3e3; border-bottom:1px solid #e3e3e3;"></td>
                       <td width="24" style="border-bottom:1px solid #e3e3e3;">&nbsp;</td>
                       <td id="PageFooterContainer" width="585" valign="top" colspan="6" style="border-bottom:1px solid #e3e3e3;padding:0px;">
    
                       </td>
    
                       <td width="29" style="border-bottom:1px solid #e3e3e3;">&nbsp;</td>
                       <td width="1" style="background:#e3e3e3; border-bottom:1px solid #e3e3e3;"></td>
                   </tr>
                  </table>
    
               </td>
               <td valign="top" width="50%"></td>
           </tr>
       </table>
    </body>
    </html>
    
  6. Разверните меню "Параметры " и для имени версии введите версию шаблона.

  7. Для темы введите {{subject}}.

  8. Выберите Сохранить.

  9. Вернитесь на страницу шаблонов транзакций , выбрав стрелку назад.

  10. Запишите идентификатор шаблона, созданного для использования на следующем шаге. Например, d-989077fbba9746e89f3f6411f596fb96. Вы указываете этот идентификатор, когда вы добавляете преобразование утверждений.

Это важно

В следующих шагах показано, как создать XML-файлы пользовательской политики. Рекомендуется использовать пример настраиваемой политики проверки электронной почты, доступной на сайте GitHub. DisplayControl_TrustFrameworkExtensions.xml использует TrustFrameworkExtensions.xml как свой базовый файл, поэтому убедитесь, что включены файлы TrustFrameworkBase.xml, TrustFrameworkLocalization.xml и TrustFrameworkExtensions.xml из SocialAndLocalAccountsначального пакета в вашу политику.

Добавьте типы утверждений Azure AD B2C

В политике добавьте в элемент <BuildingBlocks>указанные ниже типы утверждений<ClaimsSchema>.

Эти типы утверждений необходимы для создания и проверки адреса электронной почты с помощью кода однократного пароля (OTP).

<!-- 
<BuildingBlocks>
  <ClaimsSchema> -->
    <ClaimType Id="Otp">
      <DisplayName>Secondary One-time password</DisplayName>
      <DataType>string</DataType>
    </ClaimType>
    <ClaimType Id="emailRequestBody">
      <DisplayName>SendGrid request body</DisplayName>
      <DataType>string</DataType>
    </ClaimType>
    <ClaimType Id="VerificationCode">
      <DisplayName>Secondary Verification Code</DisplayName>
      <DataType>string</DataType>
      <UserHelpText>Enter your email verification code</UserHelpText>
      <UserInputType>TextBox</UserInputType>
    </ClaimType>
  <!-- 
  </ClaimsSchema>
</BuildingBlocks> -->

Добавление преобразования утверждений

Затем необходимо преобразовать утверждения, чтобы вывести строковое утверждение JSON, которое формирует текст запроса, отправленного в SendGrid.

Структура объекта JSON определяется идентификаторами в точечной нотации InputParameters и TransformationClaimTypes в InputClaims. Числа в точечной нотации представляют массивы. Значения берутся из значений InputClaims и свойств "Value" для InputParameters. Дополнительные сведения о преобразованиях утверждений JSON см. в преобразованиях утверждений JSON.

Добавьте следующее преобразование претензий в элемент <ClaimsTransformations> внутри <BuildingBlocks>. Внесите следующие обновления в XML-файл преобразования утверждений:

  • template_id Обновите значение InputParameter с идентификатором шаблона транзакции SendGrid, созданного ранее в шаблоне Create SendGrid.
  • from.email Обновите значение адреса. Используйте действующий адрес электронной почты, чтобы верификационное письмо не было помечено как спам.

    Примечание.

    Этот адрес электронной почты должен быть проверен в SendGrid в разделе "Проверка подлинности отправителя" с помощью проверки подлинности домена или проверки подлинности одного отправителя.

  • Обновите значение входного параметра personalizations.0.dynamic_template_data.subject, указав тему, подходящую для вашей организации.
<!-- 
<BuildingBlocks>
  <ClaimsTransformations> -->
    <ClaimsTransformation Id="GenerateEmailRequestBody" TransformationMethod="GenerateJson">
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="personalizations.0.to.0.email" />
        <InputClaim ClaimTypeReferenceId="otp" TransformationClaimType="personalizations.0.dynamic_template_data.otp" />
        <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="personalizations.0.dynamic_template_data.email" />
      </InputClaims>
      <InputParameters>
        <!-- Update the template_id value with the ID of your SendGrid template. -->
        <InputParameter Id="template_id" DataType="string" Value="d-989077fbba9746e89f3f6411f596fb96"/>
        <InputParameter Id="from.email" DataType="string" Value="[email protected]"/>
        <!-- Update with a subject line appropriate for your organization. -->
        <InputParameter Id="personalizations.0.dynamic_template_data.subject" DataType="string" Value="Contoso account email verification code"/>
      </InputParameters>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="emailRequestBody" TransformationClaimType="outputClaim"/>
      </OutputClaims>
    </ClaimsTransformation>
  <!--
  </ClaimsTransformations>
</BuildingBlocks> -->

Добавить определение содержимого DataUri

Под преобразованиями утверждений в пределах <BuildingBlocks>добавьте следующее ContentDefinition , чтобы ссылаться на URI данных версии 2.1.2:

<!--
<BuildingBlocks> -->
  <ContentDefinitions>
   <ContentDefinition Id="api.localaccountsignup">
      <DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.2</DataUri>
    </ContentDefinition>
    <ContentDefinition Id="api.localaccountpasswordreset">
      <DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.2</DataUri>
    </ContentDefinition>
  </ContentDefinitions>
<!--
</BuildingBlocks> -->

Создание DisplayControl

Элемент управления верификацией используется для подтверждения адреса электронной почты с помощью проверочного кода, который пользователь получает.

В этом примере элемента управления отображения настроено следующее:

  1. email Соберите тип утверждения адреса от пользователя.

  2. SendCode С помощью действия создайте код OTP и отправьте сообщение электронной почты с кодом OTP пользователю.

    Действие отправки электронного письма с кодом верификации

  3. Подождите, пока пользователь предоставит verificationCode тип утверждения с кодом, отправленным пользователю.

  4. Вернитесь обратно в email самоутверждаемый технический профиль, имеющий ссылку на этот элемент управления отображения.

В определениях содержимого, все еще в <BuildingBlocks>, добавьте в политику следующий элемент DisplayControl типа VerificationControl.

<!--
<BuildingBlocks> -->
  <DisplayControls>
    <DisplayControl Id="emailVerificationControl" UserInterfaceControlType="VerificationControl">
      <DisplayClaims>
        <DisplayClaim ClaimTypeReferenceId="email" Required="true" />
        <DisplayClaim ClaimTypeReferenceId="verificationCode" ControlClaimType="VerificationCode" Required="true" />
      </DisplayClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="email" />
      </OutputClaims>
      <Actions>
        <Action Id="SendCode">
          <ValidationClaimsExchange>
            <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="GenerateOtp" />
            <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="SendOtp" />
          </ValidationClaimsExchange>
        </Action>
        <Action Id="VerifyCode">
          <ValidationClaimsExchange>
            <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="VerifyOtp" />
          </ValidationClaimsExchange>
        </Action>
      </Actions>
    </DisplayControl>
  </DisplayControls>
<!--
</BuildingBlocks> -->

Добавьте технические профили OTP

Технический GenerateOtp профиль создает код для адреса электронной почты. Технический VerifyOtp профиль проверяет код, связанный с адресом электронной почты. Вы можете изменить конфигурацию формата и истечения срока действия однократного пароля. Дополнительные сведения о технических профилях OTP см. в разделе "Определение однократного технического профиля пароля".

Примечание.

Коды OTP, созданные протоколом Web.TPEngine.Providers.OneTimePasswordProtocolProvider, привязаны к сеансу браузера. Это означает, что пользователь может создавать уникальные коды OTP в разных сеансах браузера, которые являются допустимыми для соответствующих сеансов. В отличие от этого, код OTP, созданный встроенным поставщиком электронной почты, не зависит от сеанса браузера, поэтому если пользователь создает новый код OTP в новом сеансе браузера, он заменяет предыдущий код OTP.

Добавьте следующие технические профили в элемент <ClaimsProviders>.

<!--
<ClaimsProviders> -->
  <ClaimsProvider>
    <DisplayName>One time password technical profiles</DisplayName>
    <TechnicalProfiles>
      <TechnicalProfile Id="GenerateOtp">
        <DisplayName>Generate one time password</DisplayName>
        <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.OneTimePasswordProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        <Metadata>
          <Item Key="Operation">GenerateCode</Item>
          <Item Key="CodeExpirationInSeconds">600</Item>
          <Item Key="CodeLength">6</Item>
          <Item Key="CharacterSet">0-9</Item>
          <Item Key="NumRetryAttempts">5</Item>
          <Item Key="NumCodeGenerationAttempts">10</Item>
          <Item Key="ReuseSameCode">false</Item>
        </Metadata>
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="identifier" />
        </InputClaims>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="otp" PartnerClaimType="otpGenerated" />
        </OutputClaims>
      </TechnicalProfile>

      <TechnicalProfile Id="VerifyOtp">
        <DisplayName>Verify one time password</DisplayName>
        <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.OneTimePasswordProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        <Metadata>
          <Item Key="Operation">VerifyCode</Item>
        </Metadata>
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="identifier" />
          <InputClaim ClaimTypeReferenceId="verificationCode" PartnerClaimType="otpToVerify" />
        </InputClaims>
      </TechnicalProfile>
     </TechnicalProfiles>
  </ClaimsProvider>
<!--
</ClaimsProviders> -->

Добавление технического профиля REST API

Этот технический профиль REST API создает содержимое электронной почты (с помощью формата SendGrid). Дополнительные сведения о технических профилях RESTful см. в разделе "Определение технического профиля RESTful".

Также, как и в случае с техническими профилями OTP, добавьте следующие технические профили в элемент <ClaimsProviders>.

<ClaimsProvider>
  <DisplayName>RestfulProvider</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="SendOtp">
      <DisplayName>Use SendGrid's email API to send the code to the user</DisplayName>
      <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      <Metadata>
        <Item Key="ServiceUrl">https://api.sendgrid.com/v3/mail/send</Item>
        <Item Key="AuthenticationType">Bearer</Item>
        <Item Key="SendClaimsIn">Body</Item>
        <Item Key="ClaimUsedForRequestPayload">emailRequestBody</Item>
      </Metadata>
      <CryptographicKeys>
        <Key Id="BearerAuthenticationToken" StorageReferenceId="B2C_1A_SendGridSecret" />
      </CryptographicKeys>
      <InputClaimsTransformations>
        <InputClaimsTransformation ReferenceId="GenerateEmailRequestBody" />
      </InputClaimsTransformations>
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="emailRequestBody" />
      </InputClaims>
    </TechnicalProfile>
  </TechnicalProfiles>
</ClaimsProvider>

Создание ссылки на DisplayControl

На последнем шаге добавьте ссылку на созданный элемент DisplayControl. Переопределите существующие LocalAccountSignUpWithLogonEmail и LocalAccountDiscoveryUsingEmailAddress самоутверждаемые технические профили, настроенные в базовой политике, с помощью следующего фрагмента XML. Если вы использовали более раннюю версию политики Azure AD B2C, эти технические профили используют DisplayClaims со ссылкой на DisplayControl.

Дополнительные сведения см. в разделе "Самоутверждаемый технический профиль " и DisplayControl.

<ClaimsProvider>
  <DisplayName>Local Account</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
      <DisplayClaims>
        <DisplayClaim DisplayControlReferenceId="emailVerificationControl" />
        <DisplayClaim ClaimTypeReferenceId="displayName" Required="true" />
        <DisplayClaim ClaimTypeReferenceId="givenName" Required="true" />
        <DisplayClaim ClaimTypeReferenceId="surName" Required="true" />
        <DisplayClaim ClaimTypeReferenceId="newPassword" Required="true" />
        <DisplayClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
      </DisplayClaims>
    </TechnicalProfile>
    <TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
      <DisplayClaims>
        <DisplayClaim DisplayControlReferenceId="emailVerificationControl" />
      </DisplayClaims>
    </TechnicalProfile>
  </TechnicalProfiles>
</ClaimsProvider>

[Необязательно] Локализация электронной почты

Чтобы локализовать электронную почту, необходимо отправить локализованные строки в SendGrid или поставщику электронной почты. Например, можно локализовать тему электронной почты, текст, сообщение кода или подпись сообщения электронной почты. Для этого можно использовать преобразование утверждений GetLocalizedStringsTransformation для копирования локализованных строк в типы утверждений. Преобразование GenerateEmailRequestBody утверждений, создающее полезные данные JSON, использует входные утверждения, содержащие локализованные строки.

  1. В политике определите следующие строковые утверждения: тема, сообщение, кодIntro и подпись.

  2. Определите преобразование утверждений GetLocalizedStringsTransformation , чтобы заменить локализованные строковые значения на утверждения из шага 1.

  3. Измените трансформацию утверждений GenerateEmailRequestBody, чтобы использование входных утверждений происходило со следующим фрагментом XML.

  4. Обновите шаблон SendGrid, чтобы использовать динамические параметры вместо всех строк, локализованных Azure AD B2C.

    <ClaimsTransformation Id="GetLocalizedStringsForEmail" TransformationMethod="GetLocalizedStringsTransformation">
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="subject" TransformationClaimType="email_subject" />
        <OutputClaim ClaimTypeReferenceId="message" TransformationClaimType="email_message" />
        <OutputClaim ClaimTypeReferenceId="codeIntro" TransformationClaimType="email_code" />
        <OutputClaim ClaimTypeReferenceId="signature" TransformationClaimType="email_signature" />
      </OutputClaims>
    </ClaimsTransformation>
    <ClaimsTransformation Id="GenerateEmailRequestBody" TransformationMethod="GenerateJson">
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="personalizations.0.to.0.email" />
        <InputClaim ClaimTypeReferenceId="subject" TransformationClaimType="personalizations.0.dynamic_template_data.subject" />
        <InputClaim ClaimTypeReferenceId="otp" TransformationClaimType="personalizations.0.dynamic_template_data.otp" />
        <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="personalizations.0.dynamic_template_data.email" />
        <InputClaim ClaimTypeReferenceId="message" TransformationClaimType="personalizations.0.dynamic_template_data.message" />
        <InputClaim ClaimTypeReferenceId="codeIntro" TransformationClaimType="personalizations.0.dynamic_template_data.codeIntro" />
        <InputClaim ClaimTypeReferenceId="signature" TransformationClaimType="personalizations.0.dynamic_template_data.signature" />
      </InputClaims>
      <InputParameters>
        <InputParameter Id="template_id" DataType="string" Value="d-1234567890" />
        <InputParameter Id="from.email" DataType="string" Value="[email protected]" />
      </InputParameters>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="emailRequestBody" TransformationClaimType="outputClaim" />
      </OutputClaims>
    </ClaimsTransformation>
    
  5. Добавьте следующий элемент Localization .

    <!--
    <BuildingBlocks> -->
      <Localization Enabled="true">
        <SupportedLanguages DefaultLanguage="en" MergeBehavior="ReplaceAll">
          <SupportedLanguage>en</SupportedLanguage>
          <SupportedLanguage>es</SupportedLanguage>
        </SupportedLanguages>
        <LocalizedResources Id="api.custom-email.en">
          <LocalizedStrings>
            <!--Email template parameters-->
            <LocalizedString ElementType="GetLocalizedStringsTransformationClaimType" StringId="email_subject">Contoso account email verification code</LocalizedString>
            <LocalizedString ElementType="GetLocalizedStringsTransformationClaimType" StringId="email_message">Thanks for validating the account</LocalizedString>
            <LocalizedString ElementType="GetLocalizedStringsTransformationClaimType" StringId="email_code">Your code is</LocalizedString>
            <LocalizedString ElementType="GetLocalizedStringsTransformationClaimType" StringId="email_signature">Sincerely</LocalizedString>
          </LocalizedStrings>
        </LocalizedResources>
        <LocalizedResources Id="api.custom-email.es">
          <LocalizedStrings>
            <!--Email template parameters-->
            <LocalizedString ElementType="GetLocalizedStringsTransformationClaimType" StringId="email_subject">Código de verificación del correo electrónico de la cuenta de Contoso</LocalizedString>
            <LocalizedString ElementType="GetLocalizedStringsTransformationClaimType" StringId="email_message">Gracias por comprobar la cuenta de </LocalizedString>
            <LocalizedString ElementType="GetLocalizedStringsTransformationClaimType" StringId="email_code">Su código es</LocalizedString>
            <LocalizedString ElementType="GetLocalizedStringsTransformationClaimType" StringId="email_signature">Sinceramente</LocalizedString>
          </LocalizedStrings>
        </LocalizedResources>
      </Localization>
    <!--
    </BuildingBlocks> -->
    
  6. Добавьте ссылки на элементы LocalizedResources, обновив элемент ContentDefinitions .

    <!--
    <BuildingBlocks> -->
      <ContentDefinitions>
        <ContentDefinition Id="api.localaccountsignup">
          <DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.2</DataUri>
          <LocalizedResourcesReferences MergeBehavior="Prepend">
            <LocalizedResourcesReference Language="en" LocalizedResourcesReferenceId="api.custom-email.en" />
            <LocalizedResourcesReference Language="es" LocalizedResourcesReferenceId="api.custom-email.es" />
          </LocalizedResourcesReferences>
        </ContentDefinition>
        <ContentDefinition Id="api.localaccountpasswordreset">
          <DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.2</DataUri>
          <LocalizedResourcesReferences MergeBehavior="Prepend">
            <LocalizedResourcesReference Language="en" LocalizedResourcesReferenceId="api.custom-email.en" />
            <LocalizedResourcesReference Language="es" LocalizedResourcesReferenceId="api.custom-email.es" />
          </LocalizedResourcesReferences>
        </ContentDefinition>
      </ContentDefinitions>
    <!--
    </BuildingBlocks> -->
    
  7. Наконец, добавьте следующее преобразование входных утверждений к техническим профилям LocalAccountSignUpWithLogonEmail и LocalAccountDiscoveryUsingEmailAddress.

    <InputClaimsTransformations>
      <InputClaimsTransformation ReferenceId="GetLocalizedStringsForEmail" />
    </InputClaimsTransformations>
    

[Необязательно] Локализация пользовательского интерфейса

Элемент "Локализация" позволяет поддерживать несколько локалей или языков в политике для пользовательских сценариев. Поддержка локализации в политиках позволяет предоставлять строки, относящиеся к языку, как для элементов пользовательского интерфейса проверки, так и для сообщений об ошибках одноразового пароля. Добавьте следующую локализованную строку в локализованные ресурсы.

<LocalizedResources Id="api.custom-email.en">
  <LocalizedStrings>
    ...
    <!-- Display control UI elements-->
    <LocalizedString ElementType="DisplayControl" ElementId="emailVerificationControl" StringId="intro_msg">Verification is necessary. Please click Send button.</LocalizedString>
    <LocalizedString ElementType="DisplayControl" ElementId="emailVerificationControl" StringId="success_send_code_msg">Verification code has been sent to your inbox. Please copy it to the input box below.</LocalizedString>
    <LocalizedString ElementType="DisplayControl" ElementId="emailVerificationControl" StringId="failure_send_code_msg">We are having trouble verifying your email address. Please enter a valid email address and try again.</LocalizedString>
    <LocalizedString ElementType="DisplayControl" ElementId="emailVerificationControl" StringId="success_verify_code_msg">E-mail address verified. You can now continue.</LocalizedString>
    <LocalizedString ElementType="DisplayControl" ElementId="emailVerificationControl" StringId="failure_verify_code_msg">We are having trouble verifying your email address. Please try again.</LocalizedString>
    <LocalizedString ElementType="DisplayControl" ElementId="emailVerificationControl" StringId="but_send_code">Send verification code</LocalizedString>
    <LocalizedString ElementType="DisplayControl" ElementId="emailVerificationControl" StringId="but_verify_code">Verify code</LocalizedString>
    <LocalizedString ElementType="DisplayControl" ElementId="emailVerificationControl" StringId="but_send_new_code">Send new code</LocalizedString>
    <LocalizedString ElementType="DisplayControl" ElementId="emailVerificationControl" StringId="but_change_claims">Change e-mail</LocalizedString>
    <!-- Claims-->
    <LocalizedString ElementType="ClaimType" ElementId="VerificationCode" StringId="DisplayName">Verification Code</LocalizedString>
    <LocalizedString ElementType="ClaimType" ElementId="VerificationCode" StringId="UserHelpText">Verification code received in the email.</LocalizedString>
    <LocalizedString ElementType="ClaimType" ElementId="VerificationCode" StringId="AdminHelpText">Verification code received in the email.</LocalizedString>
    <LocalizedString ElementType="ClaimType" ElementId="email" StringId="DisplayName">Email</LocalizedString>
    <!-- Email validation error messages-->
    <LocalizedString ElementType="ErrorMessage" StringId="UserMessageIfSessionDoesNotExist">You have exceeded the maximum time allowed.</LocalizedString>
    <LocalizedString ElementType="ErrorMessage" StringId="UserMessageIfMaxRetryAttempted">You have exceeded the number of retries allowed.</LocalizedString>
    <LocalizedString ElementType="ErrorMessage" StringId="UserMessageIfMaxNumberOfCodeGenerated">You have exceeded the number of code generation attempts allowed.</LocalizedString>
    <LocalizedString ElementType="ErrorMessage" StringId="UserMessageIfInvalidCode">You have entered the wrong code.</LocalizedString>
    <LocalizedString ElementType="ErrorMessage" StringId="UserMessageIfSessionConflict">Cannot verify the code, please try again later.</LocalizedString>
    <LocalizedString ElementType="ErrorMessage" StringId="UserMessageIfVerificationFailedRetryAllowed">The verification has failed, please try again.</LocalizedString>
  </LocalizedStrings>
</LocalizedResources>