🍱

Apollo serverから、mailする(メール送信)

2021/12/30に公開

概要:

Apollo serverから、メールする例になります。

  • トークン検証の為、mongoDbを使う例になります。

構成

  • apollo-server-express
  • nodemailer
  • GraphQL
  • mongoDB

参考のコード

https://github.com/kuc-arc-f/apollo_sv_mail


準備

  • smtp 設定, config.ts

SMTP_HOST, PORT, USER, PASSWORD, from mail ADDRESS

config.ts
SMTP_HOST : "host123.example.com",
SMTP_PORT : 465,
SMTP_SECURE : true,
SMTP_AUTH_USER : "user123",
SMTP_AUTH_PASS : "123",
SEND_MAIL_ADDRESS : "from123@example.com"
  • mongoDB, token保存

  • config.ts : MONGODB_URL ,MONGODB_DB_NAME set require

mongoDB atlas , user, password, cluster , host, dbName

config.ts
MONGODB_URL: 'mongodb+srv://user123:<pass123>@cluster999.sample123.net/test',
MONGODB_DB_NAME: 'test',  

GraphQL

  • Query
  type Query {
    getToken : String
  }
  • Mutation
type Mutation {
  sendMail(token: String, to_mail: String, title: String, body:  String ): String
}

GraphQLテスト

  • token発行
query {
  getToken
}
  • mail 送信

token: 取得したトークン
to_mail: 送信先メール

mutation {
  sendMail(token: "W1bOAIoP-friD9ub41UBHCFADr0rsaGnXpAA" ,
  to_mail: "hoge@example.com"
  , title: "title-test", body: "body-123")
}


  • 送信処理

  • 改行コードはエラーの為、送信時にBRタグ変換する例です。

  • メール送信前にBRタグから、改行[\r\n] に逆変換しています。

/src/lib/LibMail.ts

LibMail.ts
const LibMail = {
  sendMail :async function(args: IArgs){
    try {
console.log(args);
      const valid = await LibCsrf.validToken(args);
      const receiverEmailAddress = args.to_mail;
      console.log(Config.SMTP_HOST);
      console.log(Config.SMTP_PORT);
      console.log(Config.SMTP_AUTH_USER);
      console.log(Config.SMTP_AUTH_PASS);
      console.log(Config.SEND_MAIL_ADDRESS);
      let transporter = mailer.createTransport({
        host: Config.SMTP_HOST,
        port: Config.SMTP_PORT,
        secure: Config.SMTP_SECURE,
        auth: {
          user: Config.SMTP_AUTH_USER,
          pass: Config.SMTP_AUTH_PASS,
        },
      });
      let body = args.body;
      body = body.replace(/<br \/>/gi, '\r\n');
      let info = await transporter.sendMail({
        from: Config.SEND_MAIL_ADDRESS,
        to: receiverEmailAddress,
        subject: args.title,
        text: body,
      });
      console.log("Message sent: %s", info.messageId);
      console.log("Preview URL: %s", mailer.getTestMessageUrl(info));     
      return "OK";
    } catch (err) {
      console.error(err);
      throw new Error('Error , sendMail');
    }          
  },

}
export default LibMail;

  • 受信確認, gmailで確認した例(下記画面)


フロント参考/ Remix

  • 参考コード

https://github.com/kuc-arc-f/remix29

  • メール画面

  • 送信画面: mail.tsx

/app/routes/mail.tsx

mail.tsx

export default function Page() {
  console.log(Config);
  const keyUid = Config.COOKIE_KEY_USER_ID;
  // state
  const [message, setMessage] = useState("");
  const [messageError, setMessageError] = useState("");
  const [token, setToken] = useState("");
  
  useEffect(() => {
    (async() => {
      const data = await client.query({
        query: gql`
        query {
          getToken
        }      
        `,
        fetchPolicy: "network-only"
      });
  console.log(data.data.getToken);  
    setToken(data.data.getToken);  
    })()    
  },[])
  let onClick = async function(){
console.log("#onClick");
console.log(token);
    const mail = document.querySelector<HTMLInputElement>('#mail');
    const title = document.querySelector<HTMLInputElement>('#title');
    const body = document.querySelector<HTMLInputElement>('#body');
    let bodyText = body.value;
    bodyText = bodyText.replace(/\r?\n/g, '<br />');
console.log(bodyText);
    const result = await client.mutate({
      mutation:gql`
      mutation {
        sendMail(token: "${token}" ,
        to_mail: "${mail.value}"
        , title: "${title.value}", body: "${bodyText}")
      }                                  
    `
    });   
    console.log(result.data);
    if(result.data.sendMail !== 'OK'){
      setMessageError("Error, Send mail");
    }else{
      setMessage("Success, Send mail");
    }
  }  
  return (
    <div className="remix__page">
      { message ? 
      <div className="alert alert-success" role="alert">{message}</div> 
      : <div /> 
      }      
      { messageError ? 
      <div className="alert alert-danger" role="alert">{messageError}</div> 
      : <div /> }       
      <main>
        <h2>Mail Send</h2>
        <hr className="my-1" />
        <div className="col-sm-6">
          <label>
            <div>mail:</div>
            <input type="text" className="form-control" name="mail" id="mail" />
          </label>
        </div>
        <div className="col-sm-6">
          <label>
            <div>Title:</div>
            <input className="form-control" type="text" name="title" id="title" />
          </label>
        </div>
        <hr className="my-1" />
        <div className="col-sm-8">
          <label>
            <div>Body-Text:</div>
            <textarea className="form-control" rows={8} name="body" id="body"></textarea>
          </label>
        </div>        
        <hr className="my-1" />
        <button onClick={() => onClick()} className="btn btn-primary">Mail-Send
        </button>
        <hr />
        {/*
        */}
      </main>
    </div>
  );
}

....

Discussion