다음을 통해 공유


SendGrid를 사용하여 사용자 지정 전자 메일 확인

중요합니다

2025년 5월 1일부터 새 고객을 위해 Azure AD B2C를 더 이상 구매할 수 없습니다. FAQ에서 자세히 알아보세요.

시작하기 전에 이 페이지의 맨 위에 있는 정책 유형 선택기를 사용하여 설정하려는 정책 유형을 선택합니다. Azure Active Directory B2C는 미리 정의된 사용자 흐름 또는 완전히 구성 가능한 사용자 지정 정책을 통해 사용자가 애플리케이션과 상호 작용하는 방법을 정의하는 두 가지 방법을 제공합니다. 이 문서에서 필요한 단계는 각 방법마다 다릅니다.

Azure AD B2C(Azure Active Directory B2C)에서 사용자 지정 전자 메일을 사용하여 애플리케이션을 사용하기 위해 등록한 사용자에게 사용자 지정 전자 메일을 보냅니다. 타사 전자 메일 공급자 SendGrid를 사용하면 고유한 전자 메일 템플릿과 보낸 사람: 주소 및 제목을 사용할 수 있으며 지역화 및 사용자 지정 OTP(일회성 암호) 설정을 지원할 수 있습니다.

이 기능은 사용자 지정 정책에만 사용할 수 있습니다. 설정 단계의 경우 이전 선택기에서 사용자 지정 정책을 선택합니다.

사용자 지정 전자 메일 확인을 사용하려면 SendGrid, Mailjet 또는 SparkPost, 사용자 지정 REST API 또는 HTTP 기반 전자 메일 공급자(사용자 포함)와 같은 타사 전자 메일 공급자를 사용해야 합니다. 이 문서에서는 SendGrid를 사용하는 솔루션을 설정하는 방법에 대해 설명합니다.

SendGrid 계정 만들기

아직 계정이 없다면 SendGrid 계정을 설정하여 시작합니다. 설정 지침은 Azure에서 SendGrid를 사용하여 전자 메일을 보내는 방법SendGrid 계정 만들기 섹션을 참조하세요.

SendGrid API 키를 만드는 섹션을 완료해야 합니다. 이후 단계에서 사용할 API 키를 기록합니다.

중요합니다

SendGrid는 고객에게 공유 IP 및 전용 IP 주소에서 전자 메일을 보낼 수 있는 기능을 제공합니다. 전용 IP 주소를 사용하는 경우 IP 주소 워밍업을 통해 고유의 평판을 제대로 구축해야 합니다. 자세한 내용은 IP 주소 예열을 참조하세요.

Azure AD B2C 정책 키 만들기

다음으로, 정책에서 참조할 Azure AD B2C 정책 키에 SendGrid API 키를 저장합니다.

  1. Azure Portal에 로그인합니다.
  2. 여러 테넌트에 액세스할 수 있는 경우 상단 메뉴의 설정 아이콘을 선택하여 디렉터리 + 구독 메뉴에서 Azure AD B2C 테넌트로 전환합니다.
  3. Azure Portal의 왼쪽 위 모서리에서 모든 서비스를 선택한 다음 , Azure AD B2C를 검색하여 선택합니다.
  4. 개요 페이지에서 ID 경험 프레임워크를 선택합니다.
  5. 정책 키를 선택한 다음 추가를 선택합니다.
  6. 옵션의 경우 수동을 선택합니다.
  7. 정책 키의 이름을 입력합니다. 예: SendGridSecret. 접두사는 B2C_1A_ 키 이름에 자동으로 추가됩니다.
  8. 비밀에서 이전에 기록한 SendGrid API 키를 입력합니다.
  9. 키 사용의 경우 서명을 선택합니다.
  10. 선택하고생성합니다.

SendGrid 템플릿 만들기

SendGrid 계정을 만들고 Azure AD B2C 정책 키에 저장된 SendGrid API 키를 사용하여 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. 이후 단계에서 사용하기 위해 만든 템플릿의 ID 를 기록합니다. 예: d-989077fbba9746e89f3f6411f596fb96. 클레임 변환을 추가할 때 이 ID를 지정합니다.

중요합니다

다음 단계에서는 사용자 지정 정책 XML 파일을 빌드하는 방법을 보여 줍니다. GitHub에서 사용할 수 있는 샘플 사용자 지정 이메일 확인 사용자 지정 정책을 사용하는 것이 좋습니다. DisplayControl_TrustFrameworkExtensions.xml는 기본 파일로 사용 TrustFrameworkExtensions.xml 되므로 정책에 TrustFrameworkBase.xmlTrustFrameworkLocalization.xml의 파일 및 TrustFrameworkExtensions.xml 파일을 포함 해야 합니다.

Azure AD B2C 클레임 유형 추가

정책에서 다음 클레임 형식을 내<ClaimsSchema>의 요소에 <BuildingBlocks> 추가합니다.

이러한 클레임 유형은 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> -->

클레임 변환 추가

다음으로 SendGrid로 전송된 요청의 본문을 형성하는 JSON 문자열 클레임을 출력하려면 클레임 변환이 필요합니다.

JSON 개체의 구조는 InputParameters의 점 표기법의 ID와 InputClaims의 TransformationClaimTypes로 정의됩니다. 점 표기법의 숫자는 배열을 의미합니다. 값은 InputClaims의 값과 InputParameters의 “Value” 속성에서 가져옵니다. JSON 클레임 변환에 대한 자세한 내용은 JSON 클레임 변환을 참조하세요.

다음 클레임 변환을 요소 <ClaimsTransformations> 내의 <BuildingBlocks>에 추가합니다. 클레임 변환 XML을 다음과 같이 업데이트합니다.

  • template_id InputParameter 값을 SendGrid 만들기 템플릿에서 이전에 만든 SendGrid 트랜잭션 템플릿의 ID로 업데이트합니다.
  • 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="my_email@mydomain.com"/>
        <!-- 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 을 추가하여 버전 2.1.2 데이터 URI를 참조합니다.

<!--
<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>에서 정책에 VerificationControl 형식의 다음 DisplayControl을 추가하세요.

<!--
<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 기술 프로필에 대한 자세한 내용은 일회성 암호 기술 프로필 정의를 참조하세요.

비고

Web.TPEngine.Providers.OneTimePasswordProtocolProvider 프로토콜에서 생성되는 OTP 코드는 브라우저 세션에 연결됩니다. 즉, 사용자는 서로 다른 브라우저 세션에서 해당 세션에 대해 각각 유효한 고유한 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에 대한 참조를 추가합니다. 다음 XML 코드 조각을 사용하여 기본 정책에 구성된 기존 LocalAccountSignUpWithLogonEmailLocalAccountDiscoveryUsingEmailAddress 자체 어설션된 기술 프로필을 재정의합니다. 이전 버전의 Azure AD B2C 정책을 사용한 경우 DisplayClaimsDisplayControl에 대한 참조와 함께 이러한 기술 프로필에서 사용됩니다.

자세한 내용은 자가 주장된 기술 프로필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 클레임 변환을 사용하여 지역화된 문자열을 클레임 형식으로 복사할 수 있습니다. JSON 페이로드를 생성하는 클레임 변환은 GenerateEmailRequestBody 지역화된 문자열을 포함하는 입력 클레임을 사용합니다.

  1. 정책에서 제목, 메시지, codeIntro 및 서명이라는 문자열 클레임을 정의합니다.

  2. 지역화된 문자열 값을 1단계의 클레임으로 대체하도록 GetLocalizedStringsTransformation 클레임 변환을 정의합니다.

  3. GenerateEmailRequestBody 다음 XML 코드 조각과 함께 입력 클레임을 사용하도록 클레임 변환을 변경합니다.

  4. Azure AD B2C가 지역화하는 모든 문자열 대신 동적 매개 변수를 사용하도록 SendGrid 템플릿을 업데이트합니다.

    <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="my_email@mydomain.com" />
      </InputParameters>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="emailRequestBody" TransformationClaimType="outputClaim" />
      </OutputClaims>
    </ClaimsTransformation>
    
  5. 다음 지역화 요소를 추가합니다.

    <!--
    <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. ContentDefinitions 요소를 업데이트하여 LocalizedResources 요소에 대한 참조를 추가합니다.

    <!--
    <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. 마지막으로, 다음 입력 클레임 변환을 LocalAccountSignUpWithLogonEmailLocalAccountDiscoveryUsingEmailAddress 기술 프로필에 추가합니다.

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

[선택 사항] UI 지역화

지역화 요소를 사용하면 사용자 경험에 대한 정책에서 여러 로캘 또는 언어를 지원할 수 있습니다. 정책의 지역화 지원을 사용하면 확인 표시 컨트롤 사용자 인터페이스 요소일회용 암호 오류 메시지 모두에 언어별 문자열을 제공할 수 있습니다. LocalizedResources에 다음 LocalizedString을 추가합니다.

<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>