[英]Microsoft graph how to retrieve ALL SingleValueLegacyExtendedProperties of an Office 365 e-mail Message
[英]Microsoft graph how to add Office 365 Voting Buttons to an e-mail Message
我曾經能夠將 Outlook 投票按鈕添加到 Microsoft Exchange Web Services (EWS) 發送的電子郵件中。 但是自從遷移到 Microsoft.Graph 以來,使用 Outlook 365 投票按鈕功能來實現發送和接收 Microsoft.Graph.Message 的功能一直沒有成功。
有誰知道如何實現這樣的功能?
我已經包含了使用 MS Graph API Java SDK 發送帶有投票按鈕的電子郵件的所有代碼。 我已經成功發送了 5 封電子郵件,但我相信其中可能仍然存在錯誤。 考慮到這一點:本軟件按“原樣”提供,不提供任何形式的明示或暗示的保證,包括但不限於適銷性、特定用途的適用性和不侵權的保證。 在任何情況下,作者或版權持有人均不對任何索賠、損害或其他責任承擔責任,無論是在合同訴訟、侵權行為或其他方面,由軟件或軟件的使用或使用或其他原因引起的或與之相關的軟件。
順便說一下,這里是使用 MS Graph API SDK for Java 發送帶有投票按鈕的電子郵件的代碼:
Message message = new Message();
message.subject = "Meet for lunch?";
ItemBody body = new ItemBody();
body.contentType = BodyType.TEXT;
body.content = "The new cafeteria is open.";
message.body = body;
EmailAddress emailAddress = new EmailAddress();
emailAddress.address = to;
Recipient toRecipient = new Recipient();
toRecipient.emailAddress = emailAddress;
message.toRecipients = List.of(toRecipient);
EmailAddress fromAddress = new EmailAddress();
fromAddress.address = sendingMailbox;
Recipient fromRecipient = new Recipient();
fromRecipient.emailAddress = fromAddress;
message.from = fromRecipient;
VotingButtonEncoder vbe = new VotingButtonEncoderImpl();
SingleValueLegacyExtendedProperty prop =
new SingleValueLegacyExtendedProperty();
prop.value = vbe.createVoteButtonsBase64String(
List.of("Yes, let's have lunch.", "No, thank you though."));
// https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxprops/e11cc753-cecf-4fdc-bec7-23304d12388a
prop.id = "Binary {00062008-0000-0000-C000-000000000046} Id 0x00008520";
List<com.microsoft.graph.options.Option> requestOptions =
new ArrayList<>();
String requestUrl = "https://graph.microsoft.com/v1.0/users/"
+ sendingMailbox + "/microsoft.graph.sendMail";
SingleValueLegacyExtendedPropertyCollectionRequestBuilder builder =
new SingleValueLegacyExtendedPropertyCollectionRequestBuilder(
requestUrl, graphClient, requestOptions);
List<SingleValueLegacyExtendedProperty> pageContents =
new ArrayList<>();
pageContents.add(prop);
SingleValueLegacyExtendedPropertyCollectionPage singleValueExtPropPage =
new SingleValueLegacyExtendedPropertyCollectionPage(
pageContents, builder);
message.singleValueExtendedProperties = singleValueExtPropPage;
boolean saveToSentItems = true;
graphClient.users(sendingMailbox)
.sendMail(UserSendMailParameterSet.newBuilder()
.withMessage(message)
.withSaveToSentItems(saveToSentItems).build())
.buildRequest().post();
投票按鈕編碼器:
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class VotingButtonEncoderImpl implements VotingButtonEncoder {
public static final String voteRequestPropHex = "0x00008520";
@Override
public String voteRequestId() {
return voteRequestPropHex;
}
@Override
public String createVoteButtonsBase64String(
Collection<String> voteOptions) throws DecoderException {
String hex = createVoteButtonsHexString(voteOptions);
byte[] bytes = Hex.decodeHex(hex.toCharArray());
return Base64.getEncoder().encodeToString(bytes);
}
@Override
public String createVoteButtonsHexString(Collection<String> voteOptions) {
// let's build a PidLidVerbStream!
// https://msdn.microsoft.com/en-us/library/ee218541(v=exchg.80).aspx
//
// that is a bit...dense...so how about the partial solution from
// Glen'S Exchange Blog
// http://gsexdev.blogspot.com/2015/01/sending-message-with-voting-buttons.html
// don't worry, as of 2017/12/11 the content there is totally A-OK. Just
// Make sure that the vote button strings are in the VoteOptionsExtra
// section.
List<VoteButtonHexifier> options =
new ArrayList<VoteButtonHexifier>(voteOptions.size());
for (String optionString : voteOptions) {
options.add(new VoteButtonHexifier(optionString));
}
String header = "0201";
// docs say count of VoteOption stuctures plus VoteOptionExtras
// structures, but appears to actually be the count of VoteOption + 4.
// Witness, here are the start of the binary from emails with 10, 9, 8,
// ... 1 voting options as created in Outlook. Look at the 4th and 5th
// hex digits which have been separated from the rest with a space.
//
// Email Options: one;two;three;four;five;six;seven;eight;nine;ten
// 0x8520: 0201 0e 00000000000000055265706c79084...
// Email Options: one;two;three;four;five;six;seven;eight;nine
// 0x8520: 0201 0d 00000000000000055265706c79084...
// Email Options: one;two;three;four;five;six;seven;eight
// 0x8520: 0201 0c 00000000000000055265706c79084...
// Email Options: one;two;three;four;five;six;seven
// 0x8520: 0201 0b 00000000000000055265706c79084...
// Email Options: one;two;three;four;five;six
// 0x8520: 0201 0a 00000000000000055265706c79084...
// Email Options: one;two;three;four;five
// 0x8520: 0201 09 00000000000000055265706c79084...
// Email Options: gov one;two;three;four
// 0x8520: 0201 08 00000000000000055265706c79084...
// Email Options: onebutton;twobutton;threebutton
// 0x8520: 0201 07 00000000000000055265706c79084...
// Email Options: onebutton;twobutton
// 0x8520: 0201 06 00000000000000055265706c79084...
// Email Options: one button
// 0x8520: 0201 05 00000000000000055265706c79084...
String recordCnt = intToLittleEndianString(options.size() + 4);
// not documented anywhere, but seems necessary
String preReplyAllPadding = "00000000";
String replyToAllHeader =
"055265706C790849504D2E4E6F7465074D657373616765025245050000000000000000";
String replyToAllFooter =
"0000000000000002000000660000000200000001000000";
String replyToHeader =
"0C5265706C7920746F20416C6C0849504D2E4E6F7465074D657373616765025245050000000000000000";
String replyToFooter = "0000000000000002000000670000000300000002000000";
String forwardHeader =
"07466F72776172640849504D2E4E6F7465074D657373616765024657050000000000000000";
String forwardFooter = "0000000000000002000000680000000400000003000000";
String replyToFolderHeader =
"0F5265706C7920746F20466F6C6465720849504D2E506F737404506F737400050000000000000000";
String replyToFolderFooter = "00000000000000020000006C00000008000000";
// Yes, each option goes in TWICE as an ANSI string with no terminator
// https://msdn.microsoft.com/en-us/library/ee218406(v=exchg.80).aspx
StringBuilder optionsAscii = new StringBuilder(2000);
int count = 0;
for (VoteButtonHexifier option : options) {
optionsAscii.append("04000000")
// option (first time)
.append(option.getAsciiHexString())
.append("0849504D2E4E6F746500")
// option (second time)
.append(option.getAsciiHexString())
// internal2 - fixed
.append("00000000"
// internal3 - fixed
+ "00"
// fUseUSHeaders:
// 00000000 = international;
// 01000000 = us
+ "00000000"
// internal4 - fixed
+ "01000000"
// send behavior (01000000 = send immediately,
// 02000000 prompt user to edit or send)
+ "01000000"
// internal5 - fixed: int 0x00000002 (little endian)
+ "02000000"
// ID: record index, 1 based. (little endian)
+ intToLittleEndianString(count++)
// internal 6 (terminator, -1)
+ "ffffffff");
}
// voting option extra bits
String VoteOptionExtras =
"0401055200650070006C00790002520045000C5200650070006C007900200074006F00200041006C006C0002520045000746006F007200770061007200640002460057000F5200650070006C007900200074006F00200046006F006C0064006500720000";
// they are in here in UTF-16LE twice and up above in ASCII twice.
// https://msdn.microsoft.com/en-us/library/ee217598(v=exchg.80).aspx
StringBuilder optionsUtf16Le = new StringBuilder(2000);
for (VoteButtonHexifier option : options) {
// UTF-16LE option (first time)
optionsUtf16Le.append(option.getUtf16LeHexString())
// UTF-16LE option (second time)
.append(option.getUtf16LeHexString());
}
String allowReplyAllVal = "00"; // false
String allowReplyVal = "00"; // false
String allowReplyToFolderVal = "00"; // false
String allowForwardVal = "00"; // false
String VerbValue = header + recordCnt + preReplyAllPadding
+ replyToAllHeader + allowReplyAllVal + replyToAllFooter
+ replyToHeader + allowReplyVal + replyToFooter + forwardHeader
+ allowForwardVal + forwardFooter + replyToFolderHeader
+ allowReplyToFolderVal + replyToFolderFooter + optionsAscii
+ VoteOptionExtras + optionsUtf16Le;
return VerbValue;
}
public static String intToLittleEndianString(int count) {
return String.format("%08x", swapEndianOrder(count));
}
public static int swapEndianOrder(int i) {
return (i & 0xff) << 24
| (i & 0xff00) << 8
| (i & 0xff0000) >> 8
| (i >> 24) & 0xff;
}
}
投票按鈕標簽需要 ASCII 和 little-endian UTF16:
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import org.apache.commons.codec.binary.Hex;
/**
* Accepts a String and produces ASCII and little-endian UTF16
* representations of those string to embed in voting buttons.
* TODO: enhance code to accept separate strings for the ASCII and UTF16
* strings to better support I18Z.
* @author Tim Perry
*/
public class VoteButtonHexifier
implements Comparable<VoteButtonHexifier> {
private String buttonLabel;
public VoteButtonHexifier(String buttonLabel) {
if (buttonLabel == null) {
throw new NullPointerException("buttonLabel may not be null");
}
this.buttonLabel = buttonLabel;
}
/**
* This will return valid ASCII characters IFF the input can be
* represented as ASCII characters. Be careful to sanitize input.
* @return the button label as the hex of UTF_8.
*/
public String getAsciiHexString() {
String buttonLabel = UnicodeCharacterUtils
.fixQuotesElipsesAndHyphens(this.buttonLabel);
String lengthHex = String.format("%02X", buttonLabel.length());
String labelHex = Hex.encodeHexString(
buttonLabel.getBytes(StandardCharsets.UTF_8));
return lengthHex + labelHex;
}
public String getUtf16LeHexString() {
String lengthHex = String.format("%02X", buttonLabel.length());
String labelUtf16_ElHex = utf16LeHex(buttonLabel);
return lengthHex + labelUtf16_ElHex;
}
private String utf16LeHex(String var) {
Charset charset = Charset.forName("UTF-16LE");
return Hex.encodeHexString(var.getBytes(charset));
}
@Override
public boolean equals(Object o) {
if (o == null || !(o instanceof VoteButtonHexifier)) {
return false;
}
VoteButtonHexifier other = (VoteButtonHexifier) o;
return buttonLabel.equals(other.buttonLabel);
}
@Override
public int hashCode() {
return buttonLabel.hashCode();
}
@Override
public int compareTo(VoteButtonHexifier o) {
if (o == null) {
return 1;
}
return buttonLabel.compareTo(o.buttonLabel);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.