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();
    }
    }

Apostille(어포스티유) 받은 FBI 범죄경력증명서 

한국 국내 거소증을 받을려면 범죄경력증명서(FBI Criminal Record)를 미국무부에서  Apostille(어포스티유)받아서 제출해야 하는 규정이 2019년 9월경에 새로 생겨서 이전에 비자를 받았거나 중간에 거소증이 만료되어서 새로 만들거나 해외에서 체류기간이 6개월이 지나면 위의 범죄경력증명서를 제출해야 한다.

복잡하지만 밑의 과정을 거쳐야 한다.먼저 밑의 1번 과정을 하면서 신청을 할때 USPS 에서  디지털 지문을 찍고 바로 FBI로 전자지문을 보내면  FBI 로부터  일레트로닉으로 결과를 받겠다고 하면 지문 채취하면서 몇시간내에 바로 이메일로 결과를 받게 된다.  문제는 다른 어포스티유는 주정부에서 받을 수 있지만 범죄기록조회서 혹은 범죄경력증명서는 미국무부에서만 발급이 된다.

 

Apostille(어포스티유) 받은 FBI 범죄경력증명서

Criminal history record check issued by FBI (①) and apostille confirmation by US Department State office of Authentications (②)

①  https://www.edo.cjis.gov/#/  and  get  finger print at USPS (appointment only)

FBI background check
FBI background check
FBI background check
FBI background check
FBI background check
FBI background check
FBI background check
FBI background check
FBI background check
FBI background check

그리고 나면 밑의 사이트의 링크에서 폼을 작성하고 리턴메일를 구입한뒤에 위에서 받은 결과를 프린트 아웃해서 보내면 서류를 받게 된다. 본인의 경우는 현재 서류를 보낸지 10여일이 지났는데도 받지 못하였다.

 

FBI background check
FBI background check

②   ​Federal Documents such as  FBI clearances are authenticated by the US Authentications Office.

https://travel.state.gov/content/travel/en/records-and-authentications/authenticate-your-document/office-of-authentications.html

 – ​Mailing Address:
U.S. Department of State Office of Authentications
CA/PPT/S/TO/AUT
44132 Mercure Cir.
PO Box 1206
Sterling, VA 20166-1206

Phone:202-485-8000
Monday through Friday

 

코비드 관련해서 미국무부의 서류 처리가 늦어져서 삼개월이 지나서 받았다. 아마도 코비드가 없었다면 일이주 내로 받을지 모르겠지만 현재 코비드 기간중에는 서류 진행이 늦은 것인지 평상시에도 그런것인지 자세한 내용은 알수 없다.  또 특히 따로 급행으로 진행되는 방법이 있는지도 확인이 된바 없다. 브로커들을 통해서 하더라도 특히 따로 빨리 되는 방법이 없을 듯 하다. 단지 서류 진행을 도움을 줄것이라고 생각된다. 범죄기록 어포스트유가 필요하다면 브로커를 시키든 개인이 직접하든 많은 시간의 여유를 두고 하는 게 좋지 않을까 생각한다.  아그리고 리터메일은 페덱스( Fedex)로 하였지만 현재 국무부는 페덱스를 사용하지 않는다고 바로 USPS를 통해서 이메일을 보냈다. 반송메일 서비스는 꼭 USPS로 사용하는게 조금이라도 지연되지 않는 방법일듯 하다.

 

 

재외동포 비자(F4) 관련 안내

국내 거소증 재발급

미국에서 3년전 즉 2018년경에 5년 단기 복수 비자를 미국 영사관에서 받은뒤에 한국에서 거소증을 발급 받았었다. 하지만 이번 코로나 사태등으로 한국 방문이 쉽지 않아 연장을 할 수 없어 그만 거소증 기간이 2년이었던것이 만료되면서 각종 관공서 서류및 은행 관련 서류등을 만들수가 없었다. 즉 거소증에 새로 발급된 거소번호가 주민등록 번호가 말소 된것처럼 사용을 할수가 없게 된것이었다.

힘들게 기회를 내어 코비드로 힘든 시기에 한국을 방문하면서 재발급을 받기로 결정 하였다. 모든 웹사이트도 그렇고 전화로 출입국 관리국에 몇번을 확인하였지만.. 복수 비자가 유효하기에 별다른 서류가 필요할 것이라고는 생각지도 않았고 그렇게 알고 있었다.

문제는 한국 출입국 관리소에서 나의 범죄기록관련 서류를 어포스티유를 받아서 제출하기를 원해서 였다,

그것도 한국에서 갑자기 서류를 원하니 난감 할수 밖에 없었고 거소증을 내줄수 없다는 것에 어쩔수 없이 서류를 한달안에 주기로 하고 임시로 거소번호만 한달간의 유예를 받고 나올 수 밖에 없었다.

다행히도 한달안에 필요한 은행업무와 관공서 서류를 준비할 수 있어서 서류처리를 끝낼 수 있었지만 각종 관련관공서나 직원들이 제대로 관련내들을 공지하지 못해 나같은 경우가 있을수 있다.

즉 현재 한국에서 범죄기록서류를 어포스티유를 받는 경우는 6개월 이상 한국에서 체류하지 않은 때이다. 물론 한국에서  거소증을 새로 신청해서 할 경우도 마찬가지이고 새로 F4 비자를 만드는 경우도 이 서류를 준비해서 제출해야 한다. 상당히 비 효율적이고 생산적이지 못한 서류이다. 더군다나 어포스티유를 받아야 한다는 것이 상당히 비효율적이다.  모든게 인터넷으로 빠르게 정보가 호환되고 있는 시대에 이 서류를 준비해야 한다는 것 자체가 시대를 역행하는 것들이다.

물론 6개월동안 한국에서 체류하지 않으면 범죄를 갖을 수 있는 기회가 많겠지만 많은 일반인들을 대상으로 하는 서류들인데 이모든게 거소증등을 쉽게 내주지 않겠다는 탁상공론식의 한국국가의 행정처리인지 답답하기만 하다.

 

Using windows putty/WINSCP with public Key that has been generated by openssl

When you are trying to remote server or hosting web server, it is not that simple with your user id and password.

Those days are gone now and you will need to provide the public key to server and you will use private key that is matched with your public key.

The first step is you will need to create a public key pair from your  windows system first as below;

Open the windows command shell and type “ssh -keygen”

After that you might have to type for the passphrase which will be the password of your key.

Then you don’t have to put any file name it will still generate at the default folder which will be the “./ssh/id_rsa.pub”.

This will make more secure on your key which will block someone can steal from your system.

 

Now you have everything is ready to use putty or winscp from your windows system.

 

For you putty you can’t just use your pair key as a private key which will have following error if you use it without any conversion.

Unable to use key file "C:\publickey\id_rsa.ppk" (OpenSSH SSH-2 private key (old PEM format))
login as: Which you will need to use puttyGEn to convert your pair key(private key) to windows tool format as below; Convert this file into the right format to use with Putty:
  1. In Puttygen, in the ‘Conversions’ menu choose ‘Import’ and load id_rsa.ppk
  2. ‘Save private key’ to a different file
  3. Use this new file with Putty, either on the connection properties menu or run Pageant (the Putty key agent) and ‘Add key’ the new file. (You can e.g. create a shortcut to pageant in your Startup menu and give it the key file name as a command line parameter so this is loaded automatically for you.)
key conversions
key conversion

Then you can point above saved new private key from putty tool as below;

 

putty_selecting_private_key
putty_selecting_private_key

After above steps, it will be smooth to get the putty session without any issue.

 

 

For the WINSCP, it will need just minor tweaking as below;

winscp_advanced_set_for_private_key
winscp_advanced_set_for_private_key

Sure it should have same conversion step as above after generate the key from openssl.

 

How to configure MS windows service to start with different type

When we set service at the MS window system, there should be configuration of starting type which can be automatic or manual way.

The below types are the specifically you can use them into the service installation;

 

The start options are

  • auto–a service automatically started at boot time, even if no user logs on
  • boot–a device driver loaded by the boot loader
  • demand–a service that must be manually started (the default)
  • disabled–a service that can’t be started
  • system–a service started during kernel initialization

And the below has the example

@echo off

echo *******
echo How To Use Script
echo _______________
echo This script must be run with Administrator priviledges.

echo –
echo Make sure you have set the binpath to the fullpath location of your XXXXXX.exe

echo –
echo If Installation fails try using ‘SC delete XXXXXXServer to uninstall any previous XXXXXX service installations
echo _____________
pause

SC create XXXXService displayname= “XXXXServer” binpath= “.\XXXXX.exe” start= auto obj= LocalSystem

pause

미국에서 – 재택근무의 실상

코비드-19 바이러스로 미국의 많은 직장인들이 재택근무를 시작하게 되었다.

소프트웨어 쪽에 있는 관계로 이전에도 재택근무를 권장하지는 않았지만 굳이 재택근무를 한다고 해도 말리지는 않았지만 몇년전부터 페이스 투 페이스 즉 직접 대면하면서 함께 사무실에 모여서 일하는 것을 더 능률이 오른다고 재택근무를 권장하지 않기 시작했다. 또한 많은 사람들이 재택근무의 효율이 떨어짐을 모두가  암묵적으로 인정하기도 했다. 아무래도 집에서 일을 하게 되면 잡다한 일에 실무에 집중하기 쉽지는 않다.  또한 리모트로 연결하기 때문에 버처머신등에 접근하는 것이 사무실에서 일하는 것보다 그리 빠르지 않기도 했다.  결국 모든 사람들이 재택근무의 효율때문에  열심히 일하는 것에 대해 많은 의심을 갖게 만들었다.

하지만 코비드가 많은 사람들을 재택근무로 묶어 놓으면서 효율을 바꾸어 놓기 시작했다. 일단 한두명이 집에서 일하는 것이 아니라 모든 사람들이 재택근무라 모두 쉽게 공동체의 분위기 속에 일을한다 즉 모두가 같은 입장이기 때문이다. 사무실에서 얼굴을 맞대고 일하면 굳이 전화기나 채팅을 않하고도 표정만 봐도 일하던것을 이제는 더 많은 대화의 시간을 갖어야 한다. 그래야만 조금이라도 더 상대편의 마음을 알 수 있기 때문이다. 그러다 보니 어느날은 하루종일 미팅만 하다가 끝나는 날이 있다. 즉 본인의 실제 일은 하지도 못하고 계속되는 미팅에 치여서 결국에는 오버타임으로 일을 자연스럽게 하게 된다. 더군다나 아침 저녁의 출퇴근 시간은 자연스럽게 일하는 시간으로 바뀌게 되었다.  일의 특성상 오프쇼어 직원들하고 같이 일을 하면서 새벽같이 미팅을 시작하게 된다.  이렇게 되다 보니 예전의 재택근무의 효율과 현재의 재택근무 효율은 하늘과 땅차이다.

다시 사무실로 돌아가는 날자를 잡지 못하는 이유중의 하나가 현재의 재택근무 능률이 굳이 사무실에서 일하는 것과 차이가 없슴을 느끼면서 비싼 사무실 임대비를 내고 직원들을 사무실로 불러야 하냐는 딜레머에 빠진 것도 사실일 것이다.

누가 뭐라고 해도 직장 동료들과 사무실에서 어울리며 공동체의 분위기를 느끼면서 일하는 감성은 재택근무에서는 절대 찿아 볼수 없다.