Sendgrid Java API (샌드그리드 자바 API)로 메일 보내기

샌드그리드를 사용하여 예전부터 이메일을 보내고 있었는데 최근들어 예전 API가 이메일을 발송하지 않아 아무래도 문제가 있는것 같아 새로운 API로 바꾸게 되었다.

사용자 입장에서는 모든게  다 바뀌었고 5-6년전부터 쓰던 API는 하나도 같은게 없었다.  아래의 내용은 샘플과 함께 문제점이 있던것을 고친 내용들이다.

  •  java API jar file download : https://github.com/sendgrid/sendgrid-java/releases/download/4.7.2/sendgrid-java.jar
  •  위의 jar file 만 따로 받아서 사용하면 되는데 그렇게 하면   아래의  error가   런타임에 생긴다.
  • java.lang.SecurityException: Invalid signature file digest for Manifest main attributes    .
  •  이럴때는 가장 쉬운 방법으로는    각종 zip 관련  도구로 META-INT folder 로들어가서  *SF,*.DSF,*RSA 파일들을 모두 지우고 jar 파일을 세이브하면 된다. 아니면 https://github.com/sendgrid/sendgrid-java 에서 코드를 다운받아서  jar 파일을 빌드할때  사이닝 관련된 파일들을 아래와 같이 제외 시킨다.

Maven:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.6</version>
    <executions>
        <execution>
            <id>unpack-dependencies</id>
            <phase>package</phase>
            <goals>
                <goal>unpack-dependencies</goal>
            </goals>
            <configuration>
                <excludeScope>system</excludeScope>
                <excludes>META-INF/*.SF</excludes>
                <excludes>META-INF/*.DSA</excludes>
                <excludes>META-INF/*.RSA</excludes>
                <excludeGroupIds>junit,org.mockito,org.hamcrest</excludeGroupIds>
                <outputDirectory>${project.build.directory}/classes</outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>

ANT:

  1. <jar destfile="app.jar" basedir="${classes.dir}">
    <zipfileset excludes="META-INF/**/*" src="${lib.dir}/bcprov-jdk16-145.jar"></zipfileset>
    <manifest>
    <attribute name="Main-Class" value="app.Main"/>
    </manifest>
    </jar>

    다음은 간단한 샘플 코드들이이다. Personalization을 사용하여 여러 사람들한테 보내거나 BCC등 예전과는 많이 다른 모습을 보인다. 물론 기본적으로 디렉트 API 에서 웹서비스 API로 바뀐게 확연히 들어난다. 

  2. import com.sendgrid.Method;
    import com.sendgrid.Request;
    import com.sendgrid.Response;
    import com.sendgrid.SendGrid;
    import com.sendgrid.helpers.mail.Mail;
    import com.sendgrid.helpers.mail.objects.*;
    import java.io.IOException;
    public class Example {
    // Fully populated Mail object
    public static Mail buildKitchenSink() {
    Mail mail = new Mail();
    Email fromEmail = new Email();
    fromEmail.setName(Example User);
    fromEmail.setEmail(test@example.com);
    mail.setFrom(fromEmail);
    mail.setSubject(Hello World from the Twilio SendGrid Java Library);
    Personalization personalization = new Personalization();
    Email to = new Email();
    to.setName(Example User);
    to.setEmail(test1@example.com);
    personalization.addTo(to);
    to.setName(Example User);
    to.setEmail(test2@example.com);
    personalization.addTo(to);
    Email cc = new Email();
    cc.setName(Example User);
    cc.setEmail(test3@example.com);
    personalization.addCc(cc);
    cc.setName(Example User);
    cc.setEmail(test4@example.com);
    personalization.addCc(cc);
    Email bcc = new Email();
    bcc.setName(Example User);
    bcc.setEmail(test5@example.com);
    personalization.addBcc(bcc);
    bcc.setName(Example User);
    bcc.setEmail(test6@example.com);
    personalization.addBcc(bcc);
    personalization.setSubject(Hello World from the Personalized Twilio SendGrid Java Library);
    personalization.addHeader(X-Test, test);
    personalization.addHeader(X-Mock, true);
    personalization.addSubstitution(%name%, Example User);
    personalization.addSubstitution(%city%, Riverside);
    personalization.addCustomArg(user_id, 343);
    personalization.addCustomArg(type, marketing);
    personalization.setSendAt(1443636843);
    mail.addPersonalization(personalization);
    Personalization personalization2 = new Personalization();
    Email to2 = new Email();
    to2.setName(Example User);
    to2.setEmail(test1@example.com);
    personalization2.addTo(to2);
    to2.setName(Example User);
    to2.setEmail(test2@example.com);
    personalization2.addTo(to2);
    Email cc2 = new Email();
    cc2.setName(Example User);
    cc2.setEmail(test3@example.com);
    personalization2.addCc(cc2);
    cc2.setName(Example User);
    cc2.setEmail(test4@example.com);
    personalization2.addCc(cc2);
    Email bcc2 = new Email();
    bcc2.setName(Example User);
    bcc2.setEmail(test5@example.com);
    personalization2.addBcc(bcc2);
    bcc2.setName(Example User);
    bcc2.setEmail(test6@example.com);
    personalization2.addBcc(bcc2);
    personalization2.setSubject(Hello World from the Personalized Twilio SendGrid Java Library);
    personalization2.addHeader(X-Test, test);
    personalization2.addHeader(X-Mock, true);
    personalization2.addSubstitution(%name%, Example User);
    personalization2.addSubstitution(%city%, Denver);
    personalization2.addCustomArg(user_id, 343);
    personalization2.addCustomArg(type, marketing);
    personalization2.setSendAt(1443636843);
    mail.addPersonalization(personalization2);
    Content content = new Content();
    content.setType(text/plain);
    content.setValue(some text here);
    mail.addContent(content);
    content.setType(text/html);
    content.setValue(<html><body>some text here</body></html>);
    mail.addContent(content);
    Attachments attachments = new Attachments();
    attachments.setContent(TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4gQ3JhcyBwdW12);
    attachments.setType(application/pdf);
    attachments.setFilename(balance_001.pdf);
    attachments.setDisposition(attachment);
    attachments.setContentId(Balance Sheet);
    mail.addAttachments(attachments);
    Attachments attachments2 = new Attachments();
    attachments2.setContent(BwdW);
    attachments2.setType(image/png);
    attachments2.setFilename(banner.png);
    attachments2.setDisposition(inline);
    attachments2.setContentId(Banner);
    mail.addAttachments(attachments2);
    mail.setTemplateId(13b8f94f-bcae-4ec6-b752-70d6cb59f932);
    mail.addSection(%section1%, Substitution Text for Section 1);
    mail.addSection(%section2%, Substitution Text for Section 2);
    mail.addHeader(X-Test1, 1);
    mail.addHeader(X-Test2, 2);
    mail.addCategory(May);
    mail.addCategory(2016);
    mail.addCustomArg(campaign, welcome);
    mail.addCustomArg(weekday, morning);
    mail.setSendAt(1443636842);
    ASM asm = new ASM();
    asm.setGroupId(99);
    asm.setGroupsToDisplay(new int[]{4, 5, 6, 7, 8});
    mail.setASM(asm);
    // This must be a valid [batch ID](https://sendgrid.com/docs/API_Reference/SMTP_API/scheduling_parameters.html) to work
    // mail.setBatchId(“sendgrid_batch_id”);
    mail.setIpPoolId(23);
    MailSettings mailSettings = new MailSettings();
    BccSettings bccSettings = new BccSettings();
    bccSettings.setEnable(true);
    bccSettings.setEmail(test@example.com);
    mailSettings.setBccSettings(bccSettings);
    Setting sandBoxMode = new Setting();
    sandBoxMode.setEnable(true);
    mailSettings.setSandboxMode(sandBoxMode);
    Setting bypassListManagement = new Setting();
    bypassListManagement.setEnable(true);
    mailSettings.setBypassListManagement(bypassListManagement);
    FooterSetting footerSetting = new FooterSetting();
    footerSetting.setEnable(true);
    footerSetting.setText(Footer Text);
    footerSetting.setHtml(<html><body>Footer Text</body></html>);
    mailSettings.setFooterSetting(footerSetting);
    SpamCheckSetting spamCheckSetting = new SpamCheckSetting();
    spamCheckSetting.setEnable(true);
    spamCheckSetting.setSpamThreshold(1);
    spamCheckSetting.setPostToUrl(https://spamcatcher.sendgrid.com);
    mailSettings.setSpamCheckSetting(spamCheckSetting);
    mail.setMailSettings(mailSettings);
    TrackingSettings trackingSettings = new TrackingSettings();
    ClickTrackingSetting clickTrackingSetting = new ClickTrackingSetting();
    clickTrackingSetting.setEnable(true);
    clickTrackingSetting.setEnableText(true);
    trackingSettings.setClickTrackingSetting(clickTrackingSetting);
    OpenTrackingSetting openTrackingSetting = new OpenTrackingSetting();
    openTrackingSetting.setEnable(true);
    openTrackingSetting.setSubstitutionTag(Optional tag to replace with the open image in the body of the message);
    trackingSettings.setOpenTrackingSetting(openTrackingSetting);
    SubscriptionTrackingSetting subscriptionTrackingSetting = new SubscriptionTrackingSetting();
    subscriptionTrackingSetting.setEnable(true);
    subscriptionTrackingSetting.setText(text to insert into the text/plain portion of the message);
    subscriptionTrackingSetting.setHtml(<html><body>html to insert into the text/html portion of the message</body></html>);
    subscriptionTrackingSetting.setSubstitutionTag(Optional tag to replace with the open image in the body of the message);
    trackingSettings.setSubscriptionTrackingSetting(subscriptionTrackingSetting);
    GoogleAnalyticsSetting googleAnalyticsSetting = new GoogleAnalyticsSetting();
    googleAnalyticsSetting.setEnable(true);
    googleAnalyticsSetting.setCampaignSource(some source);
    googleAnalyticsSetting.setCampaignTerm(some term);
    googleAnalyticsSetting.setCampaignContent(some content);
    googleAnalyticsSetting.setCampaignName(some name);
    googleAnalyticsSetting.setCampaignMedium(some medium);
    trackingSettings.setGoogleAnalyticsSetting(googleAnalyticsSetting);
    mail.setTrackingSettings(trackingSettings);
    Email replyTo = new Email();
    replyTo.setName(Example User);
    replyTo.setEmail(test@example.com);
    mail.setReplyTo(replyTo);
    return mail;
    }
    // API V3 Dynamic Template implementation
    public static Mail buildDynamicTemplate() {
    Mail mail = new Mail();
    Email fromEmail = new Email();
    fromEmail.setName(Example User);
    fromEmail.setEmail(test@example.com);
    mail.setFrom(fromEmail);
    mail.setTemplateId(d-c6dcf1f72bdd4beeb15a9aa6c72fcd2c);
    Personalization personalization = new Personalization();
    personalization.addDynamicTemplateData(name, Example User);
    personalization.addDynamicTemplateData(city, Denver);
    personalization.addTo(new Email(test@example.com));
    mail.addPersonalization(personalization);
    return mail;
    }
    // Minimum required to send an email
    public static Mail buildHelloEmail() {
    Email from = new Email(test@example.com);
    String subject = Hello World from the Twilio SendGrid Java Library;
    Email to = new Email(test@example.com);
    Content content = new Content(text/plain, some text here);
    // Note that when you use this constructor an initial personalization object
    // is created for you. It can be accessed via
    // mail.personalization.get(0) as it is a List object
    Mail mail = new Mail(from, subject, to, content);
    Email email = new Email(test2@example.com);
    mail.personalization.get(0).addTo(email);
    return mail;
    }
    public static void baselineExample() throws IOException {
    final Mail helloWorld = buildHelloEmail();
    send(helloWorld);
    }
    public static void kitchenSinkExample() throws IOException {
    final Mail kitchenSink = buildKitchenSink();
    send(kitchenSink);
    }
    public static void dynamicTemplateExample() throws IOException {
    final Mail dynamicTemplate = buildDynamicTemplate();
    send(dynamicTemplate);
    }
    private static void send(final Mail mail) throws IOException {
    final SendGrid sg = new SendGrid(System.getenv(SENDGRID_API_KEY));
    sg.addRequestHeader(X-Mock, true);
    final Request request = new Request();
    request.setMethod(Method.POST);
    request.setEndpoint(mail/send);
    request.setBody(mail.build());
    final Response response = sg.api(request);
    System.out.println(response.getStatusCode());
    System.out.println(response.getBody());
    System.out.println(response.getHeaders());
    }
    public static void main(String[] args) throws IOException {
    baselineExample();
    kitchenSinkExample();
    dynamicTemplateExample();
    }
    }

미국 시민권(US Citizenship Interview) 인터뷰 후기 (시카고 지역)

작년(2014년) 11월초에 신청을 한뒤에 한달뒤인 12월초에 핑거 프린팅(finger printing)을 하고 약 두달정도 뒤에 인터뷰 스케쥴을 보내서 이번 삼월초에 인터뷰를 와이프와 함께 끝냈다. 인터뷰 예약시간은 와이프와 함께 오전 10시 15분이었으나, 건물안에 시큐리티체크(security check) 하고 들어가서 3층에서 체크인하고 자리에 앉아서 기다리니 약 20여분정도 남았다. 자리에 앉아서 기다리다 보니 정확히 10시 10경에 나를 먼저 불러서 인터뷰하는 사람을 따라 사무실까지 갔다.

자리에 앉기전에 먼저 진실만을 이야기하겠다고 선서뒤에 자리에 앉자마자 본인임을 확인뒤  바로 시빅(Civic)문제를 준다고 하면서 여섯문제를 빠르게 답변을 주고 받았다. 너무 빠르게 진행되어서 기억도 나지 않을 정도 이지만 굳이 준비하라고 하면 씨디에 있는 내용 몇번만 연속해서 들으면 쉽게 답을 할 수 있는 것들이었다.

시험문제들은

What is freedom of religion?

What do we call the first ten amendments to the Constitution?

What are the two parts of the U.S. Congress?

If the President and the Vice President can no longer serve, who becomes President?

How many justices are on the Supreme Court?

During the Cold War, what was the main concern of the United States?

그리고 나서 바로 읽기와 쓰기를 태스트하는데 읽기는what is the capital of United States? 이에 대해 답을 쓰는 것이 쓰기시험문제였다.

그리고는 신청서를 보고 빠르게 yes no의 답을 기다리는 질문을 연속적으로 하였고  이름을 바꾸겠냐 아니냐 다시한번 확인을 하는데 처음 신청시 바꾸겠다고 했지만 마음이 바뀌었다고 하니까 신청서에 줄을 쫙쫙 그어서 캔슬했다는 것을 표시하더니… 인터뷰하는 사람이 바뻤던지 사진에 사인을 하는 것도 잊어 버리고 그냥 나왔을 정도로 정신 없이 진행 되었다. 단지 한국군대에 있었고 훈련을 받았던 것에 대해 다시 한번 물어볼 정도였고 실제로 전투나 전쟁에 참여 했냐고 해서 노우라고 답변한 정도 였다.

나머지 몇가지 서류에 사인하자 마자 바로 축하한다고 하면서 시민권 선서는 일주일에서 6주까지 기둘려야 하고 집에서 가까운곳에서 할수도 있지만 여의치 않으면 다시 같은 장소까지 나와야 한다고 하면서 와이프와 가능하면 같은 스케쥴이 될 수 있도록 해주겠다고 친절하게 설명을 해주었다.

나의 경우는 나누어준 씨디를 시험보기 일주일전부터 출퇴근 시간에 들었고 시험 보기 몇일전부터 책자를 들여보았으니 이정도면 너무 많이 공부했다는 생각이 들 정도였다.  누구든 시민권을 신청하고 인터뷰를 하시는 경우 너무 걱정을 않하셔도 될것입니다. 이 시험은 가능하면 누구든 원하는 사람들을 붙여주기 위한 시험이지 떨어뜨리기 위한 시험이 아니기 때문입니다.

그리고 정확히 몇일뒤에 시민권선서 일정이 담긴 편지를 받았고 인터뷰후 이주일 뒤에 시민권선서를 인터뷰한 같은장소에서 했다.

아침 아홉시로 예정되었고 조금 일찍도착하여 먼저 인터뷰하던 같은 대기장소에서 기다리고 있다가 아홉시가 한참 지나서 강당으로 들어가기 시작했다. 그리 일찍가지 않아도 되었을듯 기다리기 지치기 시작하였고 많은 사람들과 가족들이 모여 어수선한 분위기였다

정각 열시가 지나서부터 동영상및 초청 인사가 인사말 정도로 간단히 끝내고  단체로 자리에서 일어서서 선서등으로 마무리짖고 개인별로 시민권 증서를 나눠주기 시작했다. 소요시간은 모두 한 30여분정도 였고 복장도 청바지를 입는등 자유스러웠다.

행사가 마치고 나오는 입구에서는 투표자 신청을 입구에서 받고 있었으나 이를 제치고 바로 코스트코에 가서 여권사진을 찍어서 우체국으로 직행하였다. 시민권증서를 준 봉투안에 여권신청서가 포함되어 있기에 이를 들고 바로 우체국에 가서 여권신청을 하는데 일인당 $110 신청비용과 나중에 배달비용 $25 의 체크를 써서 주었고 이때 시민권증서를 주면 여권신청서에 첨부해서 신청하기에 받자마자 여권신청으로 손맛도 못보고 바로 떠나 보내게 되었다.  

우체국 여권담당자의 말로는 여권이 나오기전에 증서는 따로 우편으로 보내준다고 한다. 그외에 Social Security office에 들려서 시민권증서로 신분상태을 업데이트도 하여야 하고  이를 바탕으로 다니고 있던 회사에도 스테이터스를  바꿔주어야 한다고 하는데 시민권 증서를 여권신청으로 보냈으니 일단 다시 받을때까지 기다려야 함.. 여권 신청시 첨부 서류로는 단지 시민권증서와 운전면허증이었고 체크북을 꼭 갖고 가는 것도 중요하다.   그리고 여권 신청서에는 부모와 관련된 섹션은 반드시 기입하여야 한다.

시민권을 받으면서 이름을 바꾸지 않아서인지 여권신청이외에 굳이 다른것이 필요하지 않은 상태이어서 이제와서 생각해보니 이름을 바꾸지 않은것이 더 편하다고 생각됨. 굳이 바꿔서 이것 저것 서류및 은행, 운전면허등을 새롭게 바꾸는게 귀찮을 듯..

그러다 보니 현재로는 한국여권도 유효하고 한국국적상실신고도 않한 상태이기에 이중국적자(?)가 되어 버린것 같은 생각에 몇가지 인터넷으로 조사를 해보니 결국에는 한국국적상실 신고를 자연스럽게 해야 하는데 이유로는 미국 출입국시 미국 여권으로 해야하기 때문에 한국에 장기체류시 F-4비자를 받기 위해서는 국적상실신고가 앞서게 되어야 한다.

또한 한국법상으로 국적법 제15조에 따르면 “ 대한민국의 국민으로서 자진하여 외국 국적을 취득한 자는 그 외국 국적을 취득한 때에 대한민국 국적을 상실하며, 동법 제16조 제1항에 의해 국적상실 신고를 해야할 의무가 있다”고 명시돼 있다. 미국 시민권을 취득한 후 한국 국적 상실 신고를 하지 않은 수많은 한인 시민권자는 사실상 범법자(?)인 셈이다. 일각에서는 국적상실신고를 하지 않을 경우 벌금을 내게 된다고 오해하는 한인도 있으나 이는 사실과 다 르다.

국적상실 미신고에 따른 벌금이 아니라 여권과 부과된 법률 탓이다. 시민권 취득후에도 한국여권을 사용할 경우 문제가 발생하며 벌금이 부과될 수 있다. 외국 국적을 취득한 시민권자는 원칙적으로 한국여권을 사용할 수 없다. 그러나 극히 특수한 사례가 적용돼 특정 국가 사증 발급 등의 문제가 될 경우 한인 시민권자들이 한국 여권을 이용하는 경우가 있는데, 발각시 벌금을 부과받게 된다.

한국여권법 제13조 7호에는 “여권의 발급이나 재발급을 받은 사람이 외국국적을 취득하여 국적법에 따라 국적을 상실한 때에는 여권의 효력이 상실된다”고 규정돼 있으며, 여권법 제16조 1호 등에 따라 “여권의 발급 또는 재발급을 위한 제출 서류에 거짓된 사실을 기재하면 3년 이하의 징역 또는 700만원 이하의 벌금에 처해질 수 있으며 국적상실 신고를 하지 않고 한국여권을 이용해 입국할 경우에는 200만원에서 300만원 상당의 벌칙금”이 부과된다.

또한 출입국관리법 제7조 제1항에는 “유효한 여권 및 사증을 가지고 입국을 해야 한다고 명시되어 있는데 이미 효력이 상실된 한국 여권을 이용해 입국을 하면 출입국 관리법 위반으로 동법 제94조 2호에 따라 3년 이하의 징역이나 금고 또는 2천만원 이하의 벌금이 부과될 수 있다”고 규정돼 있다.

그러나 미국 시민권을 얻고 미국여권을 한국을 방문한다면 국적상실신고를 하지 않고도 아무런 제재를 받지 않기 때문에 한인들이 국적상실 신고에 그다지 신경을 쓰지 않는 것이다. 문제는 한국에 있는 각종 재산권 행사등을 하기위해서는 미국에 있는 한국영사관 출입을 해야 하고 이에따른 작업중에 자연스럽게 신분을 확인하게 되고 시민권자인 경우 국적상실신고를 해야만 서류를 만들어주기 때문에 어쩔수 없이 할 수 밖에 없다. 물론 유효한 영주권을 갖고 몇년간은 이중 국적자로 행사를 할 수 있겠지만 이는 위에 나온 내용대로 이중국적을 허용하지 않는 한국에게는 불법인적인 행위이기에 원칙적으로는 국적상실을 반드시 해야함이 올바른 행위이다.

미국에 온지 20십년만에 신분을 미국시민권자로 바꾸게 된 먼 여정이었고 여러가지 생각이 교차하게 마련입니다. 굳이 시민권까지는 생각하지는 않았지만 영주권 만기로 어찌 되었던 여행을 자유스럽게 (?) 할려면 영주권을 새로 만들어야 했고 어차피 이곳 미국에서 더 많은 생활기반을 갖고 있기에 조금더 편하게 결정을 하지 않았나 봅니다.

하지만 한국에서 병역의 모든 의무도 마치고 하다 못해 예비군 소집에도 모두 참여하여 군역필자로 국가에 충성을 하였지만 이곳 미국 시민권 신청으로 국적을 상실한다는 것의 조금 불합리하다고 본다. 미국국적과 한국국적을 이중으로 갖고 있다고 해서 이득을 보던 시대도 없어졌을 뿐더러 어떤 이득도 더 있을 수 없는데 굳이 시민권 취득과 동시에 한국국적을 상실시키는 법의 변화가 있어야 할 것 같다.

출생지의 국적 즉 한국의 국적을 지켜줌으로 인해 한국이라는 나라에 도움이 더 많이 될것이라는 것을 쉽게 간과하는 한국정부의 안이한 자세나 그저 국민들이 병역법에 모두 신경을 쓰고 있으니 인기를 얻고자 얼토당토않은 제도나 법을 만들어 버리는 한국 정치인들의 쓰레기같은 발상이 모국의 건전한 발전을 가로막는 현상임을 모두 이해해야 할 것이다.

error: Content is protected !!