필자는 전자우편 파일을 자동하는 도구를 만들면서 전자우편을 Plain Object로 만들어야 했습니다. 본 글에서는 EML 파일을 분석하여 전자우편 객체와 첨부파일 객체로 파싱 하는 내용을 설명합니다.
관련 라이브러리
- mail.jar : 전자우편을 파싱하기 위한 라이브러리
- Jsoup.jar : text/html을 평문으로 만들기 위한 라이브러리
데이터 저장 객체 선언
전자우편 객체
전자우편의 대부분의 필드를 저장합니다. 악성코드를 탐지하기 위해서 전자우편 작성 언어 메일 문서 형식과 포함된 첨부파일 및 연결 주소를 추가적으로 저장합니다.
public class MailMessage {
private String subject = null;
private String from = null;
private List<String> to = null;
private List<String> cc = null;
private List<String> bcc = null;
private Date sentDate = null;
private Date receivedDate;
private String content = null;
private String contentType = null;
private String contentCharset = null;
private String mailLanguage = null;
private boolean hasLink = false;
private Map<String, Integer> links = null;
private Map<String, List<String>> headers = null;
private List<MailAttachment> attachments = null;
public MailMessage() {
this.headers = new HashMap<String, List<String>>();
}
public MailMessage(String subject) {
this();
this.subject = subject;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getContent() {
return content;
}
public void setContentType(String contentType) {
this.contentType = contentType;
if(this.mailLanguage == null || "".equals(this.mailLanguage) && this.contentType.toLowerCase().indexOf("charset=") >= 0) {
String regex = "charset=\"?([-a-zA-Z0-9+]*)\"?";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(this.contentType);
while (m.find()) {
// if(result.indexOf(m.group()) < 0) result.add(m.group());
this.mailLanguage = m.group(1);
}
}
}
public String getContentType() {
return this.contentType;
}
public String getContentCharset() {
return contentCharset;
}
public void setContentCharset(String contentCharset) {
this.contentCharset = contentCharset;
}
public String getMailLanguage() {
return mailLanguage;
}
public void setMailLanguage(String mailLanguage) {
this.mailLanguage = mailLanguage;
}
public Date getSentDate() {
return sentDate;
}
public void setSentDate(Date sentDate) {
this.sentDate = sentDate;
}
public Date getReceivedDate() {
return receivedDate;
}
public void setReceivedDate(Date receivedDate) {
this.receivedDate = receivedDate;
}
public ArrayList<String> extractUrls(String content) {
ArrayList<String> result = new ArrayList<String>();
String regex = "(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(content);
while (m.find()) {
// if(result.indexOf(m.group()) < 0) result.add(m.group());
result.add(m.group());
}
return result;
}
public void setContent(String content) {
this.content = content;
if(content != null) {
List<String> urls = extractUrls(content);
this.links = new HashMap<String, Integer>();
if(urls != null && urls.size() > 0) {
this.hasLink = true;
for(String url : urls) {
if(this.links.containsKey(url)) {
Integer i = this.links.get(url);
this.links.put(url, new Integer(i + 1));
} else {
this.links.put(url, new Integer(1));
}
}
}
}
}
public Map<String, List<String>> getHeaders() {
return headers;
}
public List<MailAttachment> getAttachments() {
return attachments;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public List<String> getTo() {
return to;
}
public List<String> getCc() {
return cc;
}
public List<String> getBcc() {
return bcc;
}
public void addTo(String addr) {
if(this.to == null) this.to = new ArrayList<String>();
this.to.add(addr);
}
public void addCc(String addr) {
if(this.cc == null) this.cc = new ArrayList<String>();
this.cc.add(addr);
}
public void addBcc(String addr) {
if(this.bcc == null) this.bcc = new ArrayList<String>();
this.bcc.add(addr);
}
public void addHeader(String key, String value) {
List<String> values = this.headers.get(key);
if(values == null) values = new ArrayList<String>();
values.add(value);
this.headers.put(key, values);
}
public void addAttachment(MailAttachment attm) {
if(this.attachments == null) attachments = new ArrayList<MailAttachment>();
this.attachments.add(attm);
}
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("메일 제목 : ").append(this.subject).append(System.lineSeparator());
builder.append("보낸 사람 : ").append(this.from).append(System.lineSeparator());
if(this.to != null && this.to.size() > 0) {
builder.append("받는 사람 : ");
boolean first = true;
for(String addr: this.to) {
if(!first) builder.append(", ");
builder.append(addr);
first = false;
}
builder.append(System.lineSeparator());
}
if(this.cc != null && this.cc.size() > 0) {
builder.append("참조 : ");
boolean first = true;
for(String addr: this.cc) {
if(!first) builder.append(", ");
builder.append(addr);
first = false;
}
builder.append(System.lineSeparator());
}
if(this.bcc != null && this.bcc.size() > 0) {
builder.append("숨은 참조 : ");
boolean first = true;
for(String addr: this.bcc) {
if(!first) builder.append(", ");
builder.append(addr);
first = false;
}
builder.append(System.lineSeparator());
}
if(this.sentDate != null) builder.append("보낸 시각 : ").append(this.sentDate).append(System.lineSeparator());
if(this.receivedDate != null) builder.append("받은 시각 : ").append(this.receivedDate).append(System.lineSeparator());
if(this.headers != null && this.headers.size() > 0) {
builder.append("메일 헤더 : ");
builder.append(System.lineSeparator());
List<String> list = new ArrayList(this.headers.keySet());
Collections.sort(list);
for(String key : list) {
builder.append("\t" + key + " : ");
List<String> values = this.headers.get(key);
if(values.size() > 1) {
builder.append(System.lineSeparator());
boolean first = true;
for(String value: values) {
builder.append("\t\t");
builder.append(value);
builder.append(System.lineSeparator());
first = false;
}
} else {
builder.append(values.get(0));
builder.append(System.lineSeparator());
}
}
}
if(this.mailLanguage != null) {
builder.append("메일 언어 : ").append(this.mailLanguage).append(System.lineSeparator());
}
if(this.content != null) {
String content = this.content;
if(contentType != null && (
contentType.toLowerCase().indexOf("text/html") >= 0
|| contentType.toLowerCase().indexOf("application/rtf") >= 0
)
) {
// https://stackoverflow.com/questions/3607965/how-to-convert-html-text-to-plain-text
// String plainText= Jsoup.parse((String) obj).text();
// System.out.println(plainText);
content = br2nl(content);
}
if(content.length() > 500) {
content = content.substring(0, 500) + System.lineSeparator() + "......이하 생략......";
}
// content.replace("\r\n", "\r\n\t");
content = content.replace("\n", "\n\t");
builder.append("메일 형태 : ").append(contentType).append(System.lineSeparator());
builder.append("메일 내용 :").append(System.lineSeparator());
builder.append("\t").append(content).append(System.lineSeparator());
if(this.hasLink) {
// builder.append("링크 포함 여부 : 예").append(System.lineSeparator());
builder.append("링크 목록 :").append(System.lineSeparator());
List<String> list = new ArrayList(this.links.keySet());
Collections.sort(list);
for(String key : list) {
Integer count = this.links.get(key);
builder.append("\t").append(key);
if(count > 1) {
builder.append(" (").append(count).append("회").append(")");
}
builder.append(System.lineSeparator());
}
}
}
if(this.attachments != null && this.attachments.size() > 0) {
builder.append("첨부 파일 : ");
builder.append(System.lineSeparator());
for(MailAttachment attm : this.attachments) {
String attfile = attm.toString().replace("\n", "\n\t");
builder.append("\t").append(attfile).append(System.lineSeparator());
}
}
return builder.toString();
}
}
첨부파일 객체
첨부파일 객체는 파일이름과 크기 MD5, SHA1, SHA2 해쉬를 저장합니다. 또한 추후 파일의 속성을 파악하기 위해 첨부파일 관련 헤더 파일을 저장합니다.
public class MailAttachment {
private String filename = null;
private long size = 0;
private String md5 = null;
private String sha1 = null;
private String sha2 = null;
private Map<String, List<String>> headers = null;
public MailAttachment() {
this.headers = new HashMap<String, List<String>>();
}
public MailAttachment(String filename) {
this();
this.filename = filename;
}
public void setSize(long size) {
this.size = size;
}
public void setMd5(String md5) {
this.md5 = md5;
}
public String getFilename() {
return filename;
}
public long getSize() {
return size;
}
public String getMd5() {
return md5;
}
public String getSha1() {
return sha1;
}
public void setSha1(String sha1) {
this.sha1 = sha1;
}
public String getSha2() {
return sha2;
}
public void setSha2(String sha2) {
this.sha2 = sha2;
}
public Map<String, List<String>> getHeaders() {
return headers;
}
public void addHeader(String key, String value) {
List<String> values = this.headers.get(key);
if(values == null) values = new ArrayList<String>();
values.add(value);
this.headers.put(key, values);
}
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("파일 이름 : ").append(this.filename).append(System.lineSeparator());
builder.append("파일 크기 : ").append(this.size).append(System.lineSeparator());
builder.append("파일 해쉬(MD5) : ").append(this.md5).append(System.lineSeparator());
builder.append("파일 해쉬(SHA1) : ").append(this.sha1).append(System.lineSeparator());
builder.append("파일 해쉬(SHA2) : ").append(this.sha2).append(System.lineSeparator());
if(this.headers != null && this.headers.size() > 0) {
builder.append("첨부파일 헤더 : ");
builder.append(System.lineSeparator());
List<String> list = new ArrayList(this.headers.keySet());
Collections.sort(list);
for(String key : list) {
builder.append("\t" + key + " : ");
List<String> values = this.headers.get(key);
if(values.size() > 1) {
builder.append(System.lineSeparator());
boolean first = true;
for(String value: values) {
builder.append("\t\t");
builder.append(value);
builder.append(System.lineSeparator());
first = false;
}
} else {
builder.append(values.get(0));
builder.append(System.lineSeparator());
}
}
}
return builder.toString();
}
}
전자우편 파싱하기
파싱 과정에서 text/html, text/rtf 형식으로 된 전자우편 형식의 경우에는 Plain Text로 변환하는 로직을 추가하였습니다.
package eml.parser;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.file.Files;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Header;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.internet.InternetHeaders;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import javax.swing.JEditorPane;
import javax.swing.text.EditorKit;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.safety.Whitelist;
import com.sun.mail.util.BASE64DecoderStream;
@SuppressWarnings({ "unchecked", "unused" })
public class MailParser {
/**
* @param args
* @throws MessagingException
* @throws IOException
*/
public static void main(String[] args) throws MessagingException, IOException {
File dir = new File("email");
if(dir.isDirectory()) {
FilenameFilter filter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".bin");
}
};
File[] files = dir.listFiles(filter);
for(File file : files) {
System.out.println("=========================== " + file.getName() + " ===========================");
MailMessage message = new MailParser().parse(file.getPath());
System.out.println(message.toString());
System.out.println();
System.out.println();
System.out.println();
}
}
}
private static String removeAllWhiteSpace(String str){
StringTokenizer st = new StringTokenizer(str.trim());
StringBuilder sb = new StringBuilder();
while (st.hasMoreTokens()) {
sb.append(st.nextToken());
}
return sb.toString();
}
private MailMessage parse(String filePath) throws MessagingException, IOException {
MailMessage message = new MailMessage();
Properties props = System.getProperties();
props.put("mail.host", "used.mail.host.name");
props.put("mail.transports.protocol", "smtp");
Session mailSession = Session.getDefaultInstance(props, null);
InputStream source = new FileInputStream(filePath);
MimeMessage mmessage = new MimeMessage(mailSession, source);
// System.out.println("Subject : " + mmessage.getSubject());
message.setSubject(mmessage.getSubject());
try {
Address[] fromAddr = mmessage.getFrom();
// System.out.print("From : ");
for (Address address : fromAddr) {
String addr = MimeUtility.decodeText(removeAllWhiteSpace(address.toString()));
// System.out.println(addr);
message.setFrom(addr);
}
} catch(Exception e) {
// e.printStackTrace();
String[] fromAddr = mmessage.getHeader("From");
if(fromAddr != null && fromAddr.length> 0) {
// System.out.println("언어 : " + fromAddr[0]);
for (String address : fromAddr) {
String addr = MimeUtility.decodeText(removeAllWhiteSpace(address));
message.setFrom(addr);
}
}
return message;
}
// message.getContentType()
Address[] toAddr = mmessage.getRecipients(RecipientType.TO);
if(toAddr != null && toAddr.length > 0) {
// System.out.print("To : ");
for (Address address : toAddr) {
try {
String addr = MimeUtility.decodeText(removeAllWhiteSpace(address.toString()));
// System.out.println(addr);
message.addTo(addr);
} catch(Exception e) {
e.printStackTrace();
}
}
}
Address[] ccAddr = mmessage.getRecipients(RecipientType.CC);
if(ccAddr != null && ccAddr.length > 0) {
// System.out.print("CC : ");
for (Address address : ccAddr) {
try {
String addr = MimeUtility.decodeText(removeAllWhiteSpace(address.toString()));
// System.out.println(addr);
message.addCc(addr);
} catch(Exception e) {
e.printStackTrace();
}
}
}
Address[] bccAddr = mmessage.getRecipients(RecipientType.BCC);
if(bccAddr != null && bccAddr.length > 0) {
// System.out.print("BCC : ");
for (Address address : bccAddr) {
try {
String addr = MimeUtility.decodeText(removeAllWhiteSpace(address.toString()));
// System.out.println(addr);
message.addBcc(addr);
} catch(Exception e) {
e.printStackTrace();
}
}
}
// printMessageAllHeader(message);
Enumeration<Header> headers = mmessage.getAllHeaders();
while (headers.hasMoreElements()) {
Header header = headers.nextElement();
try {
String value = MimeUtility.decodeText(removeAllWhiteSpace(header.getValue()));
message.addHeader(header.getName(), value);
} catch (Exception e) {
message.addHeader(header.getName(), header.getValue());
}
}
String[] contentLanguages = mmessage.getHeader("Content-Language");
if(contentLanguages != null && contentLanguages.length > 0) {
// System.out.println("언어 : " + contentLanguages[0]);
message.setMailLanguage(contentLanguages[0]);
}
String[] mailDate = mmessage.getHeader("Date");
if(mailDate != null && mailDate.length > 0) {
message.setSentDate(mmessage.getSentDate());
message.setReceivedDate(mmessage.getReceivedDate());
}
Object objContent = mmessage.getContent();
if (objContent instanceof Multipart) {
parseMultipart(message, (Multipart) objContent);
} else {
// System.out.println(objContent);
message.setContent((String) objContent);
}
return message;
}
private void parseMultipart(MailMessage message, Multipart mp) throws IOException, MessagingException {
MimeMultipart mm = (MimeMultipart) mp;
int bodyCount = mm.getCount();
// System.out.println("Multipart Count : " + mm.getCount());
for (int i = 0; i < bodyCount; i++) {
BodyPart bp = mm.getBodyPart(i);
// System.out.println("Headers :");
// printAllHeaders(bp.getAllHeaders());
// System.out.println("Body :");
parseBody(message, bp);
}
}
public static String toHTML(File file) throws Exception {
JEditorPane p = new JEditorPane();
p.setContentType("text/rtf");
EditorKit kitRtf = p.getEditorKitForContentType("text/rtf");
kitRtf.read(new FileReader(file), p.getDocument(), 0);
kitRtf = null;
EditorKit kitHtml = p.getEditorKitForContentType("text/html");
Writer writer = new StringWriter();
kitHtml.write(writer, p.getDocument(), 0, p.getDocument().getLength());
return writer.toString();
}
private static String hexEncode(byte[] bytes) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
public static String[] makeFileHashes(String filename) throws Exception {
InputStream fis = new FileInputStream(filename);
byte[] buffer = new byte[1024];
MessageDigest md5 = MessageDigest.getInstance("MD5");
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
MessageDigest sha2 = MessageDigest.getInstance("SHA-256");
int numRead = -1;
do {
numRead = fis.read(buffer);
if (numRead > 0) {
md5.update(buffer, 0, numRead);
sha1.update(buffer, 0, numRead);
sha2.update(buffer, 0, numRead);
}
} while (numRead != -1);
fis.close();
return new String[] {
hexEncode(md5.digest()),
hexEncode(sha1.digest()),
hexEncode(sha2.digest())
};
}
private void parseBody(MailMessage message, BodyPart bp) throws IOException, MessagingException {
Object obj = bp.getContent();
String contentType = bp.getContentType();
if (obj instanceof BASE64DecoderStream) {
// String[] aaa = bp.getHeader("Content-Disposition");
// if(aaa != null && aaa.length > 0) {
// System.out.println("\tContent-Disposition : " + aaa[0]);
// }
BASE64DecoderStream newObj = (BASE64DecoderStream) obj;
String originfilename = bp.getFileName();
// System.out.println("FileName : " + originfilename);
if(originfilename == null || "".equals(originfilename)) {
originfilename = "unknown.attachments";
}
String filename = MimeUtility.decodeText(originfilename);
File attachFile = new File("attachment" + File.separator + filename);
FileOutputStream fos = new FileOutputStream(attachFile);
byte[] buffer = new byte[1024];
int read = 0;
while ((read = newObj.read(buffer)) != -1) {
fos.write(buffer, 0, read);
}
newObj.close();
fos.close();
if(contentType.indexOf("application/rtf") >= 0) {
try {
String html = toHTML(attachFile);
message.setContentType(contentType);
message.setContent(html);
attachFile.delete();
// System.out.println("Rtf => Html :" + html);
} catch(Exception e) {
}
} else {
long size = attachFile.length();
// System.out.println("File Size :" + size);
MailAttachment attm = new MailAttachment(filename);
attm.setSize(size);
try {
String[] hashes = makeFileHashes(attachFile.getPath());
attm.setMd5(hashes[0]);
attm.setSha1(hashes[1]);
attm.setSha2(hashes[2]);
} catch(Exception e) {
}
// printAllHeaders(bp.getAllHeaders());
Enumeration<Header> headers = bp.getAllHeaders();
while (headers.hasMoreElements()) {
Header header = headers.nextElement();
try {
String value = MimeUtility.decodeText(removeAllWhiteSpace(header.getValue()));
attm.addHeader(header.getName(), value);
} catch (Exception e) {
attm.addHeader(header.getName(), header.getValue());
}
}
message.addAttachment(attm);
attachFile.delete();
// System.out.println("\tFilename : " + filename);
}
} else if(obj instanceof Multipart) {
parseMultipart(message, (Multipart) obj);
} else {
// System.out.println("\tBody Type : " + bp.getContentType());
message.setContentType(contentType);
message.setContent((String) obj);
}
}
private static String br2nl(String html) {
if (html == null)
return html;
Document document = Jsoup.parse(html);
//makes html() preserve linebreaks and spacing
document.outputSettings(new Document.OutputSettings().prettyPrint(false));
document.select("br").append("\\n");
// document.select("p").prepend("\\n\\n");
document.select("p").prepend("\\n");
return document.text().replaceAll("\\\\n", "\n");
// String s = document.html().replaceAll("\\\\n", "\n");
// return Jsoup.clean(s, "", Whitelist.none(), new Document.OutputSettings().prettyPrint(false));
}
private static void printAllHeaders(Enumeration<Header> enumHeaders) throws MessagingException {
// Enumeration<Header> enumHeaders = bp.getAllHeaders();
int index = 1;
while (enumHeaders.hasMoreElements()) {
Header aa = enumHeaders.nextElement();
try {
System.out.println("\t" + index + ". " + aa.getName() + " : " + MimeUtility.decodeText(aa.getValue()));
} catch (Exception e) {
System.out.println("\t" + index + ". " + aa.getName() + " : " + aa.getValue());
}
index++;
}
}
}
출력된 값 예시
아래와 같이 메일 정보가 출력됩니다. 전자우편의 상세정보 및 첨부파일, 연결 주소 정보도 같이 출력됩니다.
========================== eff09767507dd41710d9c7806a7c9682.bin ===========================
메일 제목 : AW: wire confirmation
보낸 사람 : "MENUEL,Karine"<kmenu@kidilizgroup.com>
받는 사람 : kmenu@kidilizgroup.com
보낸 시각 : Wed Oct 21 14:42:24 KST 2020
메일 헤더 :
Content-Type : multipart/mixed;boundary="----=_NextPart_000_0076_01C2A9A6.421423E6"
Date : Tue,20Oct202022:42:24-0700
Delivered-To : banned-quarantine
From : "MENUEL,Karine"<kmenu@kidilizgroup.com>
MIME-Version : 1.0
Message-ID : <4C15202F851E4E59B47AD133EEEE3306.MAI@home>
Received :
fromunknownbylocalhost(amavisd-new,unixsocket)id4mLpTkgoGkflfor<isavu@electroputere.ro>;Thu,22Oct202020:13:41+0300(EEST)
fromGUEST.home(unknown[45.63.67.54])byspin.electroputere.ro(amavisd-milter)withESMTPSid09MHDVUc018555;Thu,22Oct202005:00:04+0300(envelope-from<kmenu@kidilizgroup.com>)
fromUser([23.92.220.201])byhomewithMailEnableESMTPA;Wed,21Oct202002:43:18-0300
Reply-To : <kmenu@kidilizgroup.com>
Return-Path : <>
Subject : AW:wireconfirmation
To : kmenu@kidilizgroup.com
X-Amavis-Alert : BANNED,messagecontains.exe,.exe-ms,Wire.exe
X-Envelope-From : <kmenu@kidilizgroup.com>
X-Envelope-To : <isavu@electroputere.ro>
X-Envelope-To-Blocked : <isavu@electroputere.ro>
X-MSMail-Priority : Normal
X-Mailer : MicrosoftOutlookExpress6.00.2600.0000
X-MimeOLE : ProducedByMicrosoftMimeOLEV6.00.2600.0000
X-Priority : 3
X-Quarantine-ID : <4mLpTkgoGkfl>
X-Spam-Flag : NO
X-Spam-Level :
X-Spam-Score : 0
X-Spam-Status : No,score=xtag=xtag2=xkill=xtests=[]autolearn=unavailable
메일 언어 : Windows-1251
메일 형태 : text/html;
charset="Windows-1251"
메일 내용 :
Dear Sir,
Hope you are fine?
Attached is the Payment updated sheet of All Open POs ,Pls kindly check.
Pls kindly see the wire confirmation of the shippment for LOT#6288 1*40HQ .thanks.
Best regards
Karine MENUEL/Head of licences 18 Rue Emile COUE
10000 TROYES-FRANCE +33 (0)3 25 42 53 91 | +33 (0)6 07 09 81 31 kmenul@kidilizgroup.com kidilizgroup.com
링크 목록 :
http://www.kidilizgroup.com/?utm_source=signature_kg
https://ci5.googleusercontent.com/proxy/lRib70HBR-upD_d69XB4aQ8Nc0gK-nKXqFnxOyRm44SyVWsucWN3FK5LOOHaV2DDU2r_uGW6Q2MwD6gzBxd0uJ4UZScITmFYCZyKH-pINw=s0-d-e1-ft#http://www.kidilizgroup.com/signature/images/logo-ico-fb.jpg
https://ci6.googleusercontent.com/proxy/c9F7KmSX20gZuyX3kJWtWQAeaIPX3OPYnVmSSNbp2Ds_CjYHQwy0mcqlOZ2tL-DVK6AM0OrzPUySIIBe5NWYNaRUH6EyoC0j_H6PU_dK=s0-d-e1-ft#https://www.kidilizgroup.com/signature/images/logo-anim.gif
https://www.facebook.com/kidilizgroup/
https://www.google.com/url?q=http://www.kidilizgroup.com/?utm_source%3Dsignature_kg&source=gmail&ust=1589336665669000&usg=AFQjCNFzJGx4zAC__TwIiMcs4ccEN_4Xjg
https://www.google.com/url?q=https://www.facebook.com/kidilizgroup/&source=gmail&ust=1589336665669000&usg=AFQjCNFY34DjlJNyJvWM5wv06t0a_ylk4w
첨부 파일 :
파일 이름 : Wire.rar
파일 크기 : 206245
파일 해쉬(MD5) : 70ab3a298edc963db01c4dd24a077a73
파일 해쉬(SHA1) : 1ffdb110ed22f6897a390e5551a4560a2e92b4ef
파일 해쉬(SHA2) : 1ab26e8d8331d1b03920c2e48c513b237f7dcd72f5c41aae686da5266c99cff0
첨부파일 헤더 :
Content-Disposition : attachment;filename="Wire.rar"
Content-Transfer-Encoding : base64
Content-Type : application/octet-stream;name="Wire.rar"
참고자료
728x90
'Tips, Tricks > Java, Spring Framework' 카테고리의 다른 글
Java 사용자 디렉토리 찾기 (0) | 2024.11.18 |
---|---|
Convert text/rtf to text/html, text/html to text/plain(text/rtf, text/html을 text로 변환하기) (0) | 2021.01.07 |
Using a FilenameFilter in Java(자바에서 FilenameFilter 사용하기) (0) | 2021.01.06 |
Create multi WAR for a single maven project(단일 Maven 프로젝트에서 여러 개의 WAR 만들기) (0) | 2020.12.10 |
Find links from a web page(웹페이지에서 링크 찾기) (0) | 2020.12.10 |