We use mailComposeController to send emails with attachments from our iOS app. This works correctly on iOS devices. On Mac devices running Monterey 12.2, email sends as intended and attachments appear correctly in the displayed mailComposeController. However, once sent, the recipient gets what appears to be an un-openable copy of the attachment, along with the correct attachment. Extract of code, below:
if MFMailComposeViewController.canSendMail() {
let mailComposer = MFMailComposeViewController()
mailComposer.mailComposeDelegate = self
mailComposer.setToRecipients(recipients)
mailComposer.setMessageBody(body, isHTML: true)
mailComposer.setSubject(subject)
mailComposer.addAttachmentData(theData!, mimeType:(theMIMEType?.rawValue) ?? ".pdf", fileName: fileName)
present(mailComposer, animated: true, completion: nil)
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
//code here handles result of send attempt
}
As noted above, code runs correctly on iOS devices, but generates "ghost" image of attachment in sent email on Mac devices running on Apple Silicon. Thoughts much appreciated!
Related
Hi I'm tying to make a say command that sends attachments that was sent while using the command for example someone uses !say while attaching 3 attachment and it sends the 3 attachments last time I tried to do it I could only get the first attachment but I want to get all the attachments that was attached with the message
If you want to get the files or images that are attached to a message, you can access the attachments property of the message object. This will return a Collection of attachments that you can iterate through and attach to your new message.
e.g.
client.on("message", message => {
if (message.attachments) {
let attachments = message.attachments;
for (let file of attachments) {
message.channel.send({files: [file]});
}
}
})
You can get more information about this in the Discord.js documentation.
I developed a bot for Microsoft Teams using the Microsoft Bot Framework v4 Nodejs SDK (botbuilder-sdk for nodejs). We have implemented the bot in such a way that, when we receive data using a REST API call from one of our CRMs, the data is posted to the channels on Microsoft Teams. However, when I do that, we do not receive a notification on the devices. Has anyone faced such an issue?
I am saving the context state initially. Everytime we receive data from a CRM, I am incrementing the activity id of the message (to send it as a new message and not a reply) and sending it to Microsoft Teams using context.sendActivity().
When we receive that adaptive card, we do not receive a notification in the activity feed or on any of the devices.
I have gone through all the steps as you described above. I've also gone through the troubleshooting steps. However, it still doesn't give me a notification for the card. However, when I initiate a conversation with the bot, I get a notification when the bot responds.
https://i.stack.imgur.com/Bi4fc.png
https://i.stack.imgur.com/ab6uP.png
In this image, I get a notification when I get the TMS Bot started! message. However, I don't get a notification for the next two messages.
Edit: OP and I have exchanged a few emails to get this answered. This answer, as a whole, is good information for accomplishing Teams Proactive messaging, in general, but the main answer is in the last section, Simplified Code.
This is a long answer that covers many areas, simply because I'm not 100% sure I know what kind of notification you aren't receiving.
Troubleshooting
Troubleshooting Guide
Pay special attention to the many areas where notifications need to be enabled
In particular, the user may need to "Follow" and/or "Favorite" the channel to receive notifications from it
If a user has the desktop app open, they will receive the notification there and will not receive one on their phone unless they have been inactive on the desktop app for 3+ minutes. Otherwise, it's likely a bug in Teams.
Chat Notifications
If you've followed the Troubleshooting Guide linked above, your users should receive chat notifications. If not, you can try updating your MS Teams desktop or mobile client. As #KyleDelaney mentioned, it may be helpful to # mention users and/or channels
Activity Feed Notifications
You can also create Activity Feed Notifications. The gist of it is that you need to:
Include text and summary in the message
Include channelData that sets notifications.alert to true
This code will accomplish that:
const msg = MessageFactory.text('my message');
msg.summary = 'my summary';
msg.channelData = {
notification: {
alert: true,
},
};
return await dc.context.sendActivity(msg);
Result:
Note: If your bot only creates notifications and doesn't have conversations, you may benefit from creating a notifications-only bot.
Full Implementation Code
import * as adaptiveCard from '../src/adaptiveCard.json';
...
const card = CardFactory.adaptiveCard(adaptiveCard);
const activity = {
attachments: [card],
text: 'Test Card',
summary: 'my summary',
channelData: {
notification: {
alert: true,
},
},
};
await turnContext.sendActivity(activity);
Result:
Using the Teams Extension
There's a Teams Extension for BobBuilder V4 that's currently in Beta, but seems to accomplish what you need. I believe the reason you weren't getting notifications while using the above is because your bot is creating a new reply chain in the channel and not replying directly to a user. I believe you can do all of this without the extension (by manually editing activity/context properties), but the extension should make it easier.
Here's the code I used to get working notifications within a channel:
In index.js (or app.js):
import * as teams from 'botbuilder-teams';
[...]
// Change existing to use "new teams.TeamsAdapter..."
const adapter = new teams.TeamsAdapter({
appId: endpointConfig.appId || process.env.microsoftAppID,
appPassword: endpointConfig.appPassword || process.env.microsoftAppPassword,
});
Wherever you're sending the message:
import * as teams from 'botbuilder-teams';
import * as adaptiveCard from '../src/adaptiveCard.json';
...
const card = CardFactory.adaptiveCard(adaptiveCard);
const activity = {
attachments: [card],
text: 'Test Card',
summary: 'my summary',
channelData: {
notification: {
alert: true,
},
},
};
const adapter = context.adapter as teams.TeamsAdapter;
await adapter.createReplyChain(context, [activity]);
Simplified Code
OP and I have emailed back and forth a bit and the key issue is that he needed to add the trustServiceUrl code from below. Normally, this manifests itself with a 500 error, but in this case, it appears to not create notifications.. After significant testing, here's all you really have to do to send different notifications to different channels. It basically amounts to setting a couple of properties of turncontext.activity and trusting the serviceUrl. No touching activity ID or using the Teams Extension at all. My code below is how I sent messages from Emulator that could then send cards to different Teams channels:
public onTurn = async (turnContext: TurnContext) => {
const dc = await this.dialogs.createContext(turnContext);
const dialogResult = await dc.continueDialog();
// Route message from Emulator to Teams Channel - I can send "1", "2", or "3" in emulator and bot will create message for Channel
let teamsChannel;
switch (turnContext.activity.text) {
// You can get teamsChannel IDs from turnContext.activity.channelData.channel.id
case '1':
teamsChannel = '19:8d60061c3d104exxxxxxxxxxxxxxxxxx#thread.skype';
break;
case '2':
teamsChannel = '19:0e477430ebad4exxxxxxxxxxxxxxxxxx#thread.skype';
break;
case '3':
teamsChannel = '19:55c1c5fb0d304exxxxxxxxxxxxxxxxx0#thread.skype';
break;
default:
break;
}
if (teamsChannel) {
const card = CardFactory.adaptiveCard(adaptiveCard);
const activity = {
attachments: [card],
summary: 'my summary',
text: 'Test Card',
};
const serviceUrl = 'https://smba.trafficmanager.net/amer/';
turnContext.activity.conversation.id = teamsChannel;
turnContext.activity.serviceUrl = serviceUrl;
// This ensures that your bot can send to Teams
MicrosoftAppCredentials.trustServiceUrl(serviceUrl);
await turnContext.sendActivity(activity);
} else {
[...Normal onTurn Code...]
await this.conversationState.saveChanges(turnContext);
}
Note: To receive notifications, you and your users must follow the channel.
I have gone through all the steps as you described above. I've also gone through the troubleshooting steps. However, it still doesn't give me a notification for the card. However, when I initiate a conversation with the bot, I get a notification when the bot responds.
https://i.stack.imgur.com/Bi4fc.png
https://i.stack.imgur.com/ab6uP.png
In this image, I get a notification when I get the TMS Bot started! message. However, I don't get a notification for the next two messages.
I have a Notification Hub in Azure to send PUSH to Android and iOS devices. Everything is working well in Android. In iOS I have this problem:
I turn off the WiFi or I turn off the device
I send chat messages to my app (push notifications) and also messages to that device from WhatsApp.
I turn on the WiFi or turn on the device after a few minutes
I receive all the WhatsApp messages notifications but no one of the notification to my App. If the device and Internet is on, I receive the notifications without problem.
My question is: Anyone has experienced something like that or know how to fix it?
At least I should have to receive the last push, right?
I'm sending the push to a tag. I can see the Device registered in the hub either when WiFi or iPhone are off.
When sending notification ensure that you set the expiration. Default value is zero. Hence, APNs treats the notification as if it expires immediately and does not store the notification or attempt to redeliver it.
https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html
apns-expiration
If this value is nonzero, APNs stores the notification
and tries to deliver it at least once, repeating the attempt as needed
if it is unable to deliver the notification the first time. If the
value is 0, APNs treats the notification as if it expires immediately
and does not store the notification or attempt to redeliver it.
If you are using template notifications, here is how you do it.
AppleTemplateRegistrationDescription registration = new AppleTemplateRegistrationDescription(parameters.registrationID)
{ BodyTemplate = new CDataMember("{\"aps\":{\"alert\":\"$(body)\",\"payload\":\"$(payload)\",\"deeplinking\":\"$(deeplinking)\",\"category\":\"$(category)\",\"image\":\"$(image)\"}}"),
Tags = itags,
Expiry = "$(APNS_Expiry)"
};
As part of send, you can pass the expiry value.
var notification = new TemplateNotification(new Dictionary<string, string>()
{
{"APNS_Expiry", DateTime.UtcNow.AddMinutes(10).ToString("o") }, //Timestamp
{"body", NotificationText},
{"payload", NotificationText},
{"deeplinking", payload},
});
var Responsehub = hub.SendNotificationAsync(notification);
If you are using native notifications,
// Native notification
var notification = new AppleNotification(#"
{
""aps"": {
""alert"":""New notification!""
}
}");
notification.Expiry = DateTime.UtcNow.AddMinutes(2);
await notificationHubClient.SendNotificationAsync(notification);
If you are using template notifications, here is how you do it.
AppleTemplateRegistrationDescription registration = new AppleTemplateRegistrationDescription(parameters.registrationID)
{ BodyTemplate = new CDataMember("{\"aps\":{\"alert\":\"$(body)\",\"payload\":\"$(payload)\",\"deeplinking\":\"$(deeplinking)\",\"category\":\"$(category)\",\"image\":\"$(image)\"}}"),
Tags = itags,
Expiry = "$(APNS_Expiry)"
};
As part of send, you can pass the expiry value.
var notification = new TemplateNotification(new Dictionary<string, string>()
{
{"APNS_Expiry", DateTime.UtcNow.AddMinutes(10).ToString("o") }, //Timestamp
{"body", NotificationText},
{"payload", NotificationText},
{"deeplinking", payload},
});
var Responsehub = hub.SendNotificationAsync(notification);
If you are using native notifications,
// Native notification
var notification = new AppleNotification(#"
{
""aps"": {
""alert"":""New notification!""
}
}");
notification.Expiry = DateTime.UtcNow.AddMinutes(2);
await notificationHubClient.SendNotificationAsync(notification);
I was trying to write an Email sending code for Windows Phone Universal App. This is the Code that I have written in my Event Handler:
Windows.ApplicationModel.Email.EmailMessage email = new Windows.ApplicationModel.Email.EmailMessage();
email.Subject = "Good morning";
email.Body = "Hello, how are you?";
var emailRecipient = new Windows.ApplicationModel.Email.EmailRecipient(email.Address);
email.To.Add(emailRecipient);
await Windows.ApplicationModel.Email.EmailManager.ShowComposeNewEmailAsync(email);
This code works for my Windows Phone 8.1 App. But it's not working in the Universal App. Shall I have to add any reference? Is there any way to make it work in the Universal app?
Thanks a lot. :)
In Windows Store App, Windows.ApplicationModel.Email namespace is not supported.
See EmailMessage class in MSDN.
You can send mail use mailto protocol, and use LaunchUriAsync method. like this:
await Launcher.LaunchUriAsync(
new Uri(
"mailto:someemail#somedomain.com?subject=SomeSubject&body=mail content"
));
In UWP development, a lot of codes still same with Windows Phone 8.1 /Windows Store App. As below shown send an email with attachment.
EmailMessage email = new EmailMessage();
email.To.Add(new EmailRecipient("test#developerpublish.com"));
email.Subject = "Blog pos`enter code here`t by #isenthil";
var file = await GetTextFile();
email.Attachments.Add(new EmailAttachment(file.Name, file));
await EmailManager.ShowComposeNewEmailAsync(email);
I have a midlet which sends an sms to a desired number. The midlet works fine on Nokia N70 and Nokia 6300. But while using on Samsung Champ, I am able to send an SMS only once to a certain number i.e. it works fine when sending SMS to a number but it does not work when the same or a different SMS is sent to the SAME number. It does not give any exception(s) or error(s). Here is the code I am using:
public boolean sendSMS(String contactNum, String payloadText) {
try {
String addr = "sms://" + contactNum;
MessageConnection conn = (MessageConnection) Connector.open(addr);
TextMessage msg = (TextMessage) conn.newMessage(MessageConnection.TEXT_MESSAGE);
msg.setPayloadText(payloadText);
if (conn.numberOfSegments(msg) == 0) {
return false;
}
conn.send(msg);
} catch (Exception e) {
new AlertDialog("Exception", "Exception in sendSMS() occurred", "OK").show();
}
return true;
}
Please somebody guide me in this regard.
Thanks.
I suppose problem related to SMS port. It's not recommended to use port=0 (aka phone SMS INBOX port number). Some models even restricts usage of port #0. So try to use another port, e.g. 5000 or so. But in this case SMS won't be directed to SMS INBOX, so you have to write another midlet which will listen incoming SMS on port:5000